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(TestTimeZoneInLocale);
92     TESTCASE_AUTO(TestRoundtripWithCalendar);
93     TESTCASE_AUTO(Test6338);
94     TESTCASE_AUTO(Test6726);
95     TESTCASE_AUTO(TestGMTParsing);
96     TESTCASE_AUTO(Test6880);
97     TESTCASE_AUTO(TestISOEra);
98     TESTCASE_AUTO(TestFormalChineseDate);
99     TESTCASE_AUTO(TestNumberAsStringParsing);
100     TESTCASE_AUTO(TestStandAloneGMTParse);
101     TESTCASE_AUTO(TestParsePosition);
102     TESTCASE_AUTO(TestMonthPatterns);
103     TESTCASE_AUTO(TestContext);
104     TESTCASE_AUTO(TestNonGregoFmtParse);
105     TESTCASE_AUTO(TestFormatsWithNumberSystems);
106     /*
107     TESTCASE_AUTO(TestRelativeError);
108     TESTCASE_AUTO(TestRelativeOther);
109     */
110     TESTCASE_AUTO(TestDotAndAtLeniency);
111     TESTCASE_AUTO(TestDateFormatLeniency);
112     TESTCASE_AUTO(TestParseMultiPatternMatch);
113 
114     TESTCASE_AUTO(TestParseLeniencyAPIs);
115     TESTCASE_AUTO(TestNumberFormatOverride);
116     TESTCASE_AUTO(TestCreateInstanceForSkeleton);
117     TESTCASE_AUTO(TestCreateInstanceForSkeletonDefault);
118     TESTCASE_AUTO(TestCreateInstanceForSkeletonWithCalendar);
119     TESTCASE_AUTO(TestDFSCreateForLocaleNonGregorianLocale);
120     TESTCASE_AUTO(TestDFSCreateForLocaleWithCalendarInLocale);
121     TESTCASE_AUTO(TestChangeCalendar);
122 
123     TESTCASE_AUTO(TestPatternFromSkeleton);
124 
125     TESTCASE_AUTO(TestAmPmMidnightNoon);
126     TESTCASE_AUTO(TestFlexibleDayPeriod);
127     TESTCASE_AUTO(TestDayPeriodWithLocales);
128     TESTCASE_AUTO(TestMinuteSecondFieldsInOddPlaces);
129     TESTCASE_AUTO(TestDayPeriodParsing);
130     TESTCASE_AUTO(TestParseRegression13744);
131     TESTCASE_AUTO(TestAdoptCalendarLeak);
132     TESTCASE_AUTO(Test20741_ABFields);
133 
134     TESTCASE_AUTO_END;
135 }
136 
TestPatterns()137 void DateFormatTest::TestPatterns() {
138     static const struct {
139         const char *actualPattern;
140         const char *expectedPattern;
141         const char *localeID;
142         const char *expectedLocalPattern;
143     } EXPECTED[] = {
144         {UDAT_YEAR, "y","en","y"},
145 
146         {UDAT_QUARTER, "QQQQ", "en", "QQQQ"},
147         {UDAT_ABBR_QUARTER, "QQQ", "en", "QQQ"},
148         {UDAT_YEAR_QUARTER, "yQQQQ", "en", "QQQQ y"},
149         {UDAT_YEAR_ABBR_QUARTER, "yQQQ", "en", "QQQ y"},
150 
151         {UDAT_NUM_MONTH, "M", "en", "L"},
152         {UDAT_ABBR_MONTH, "MMM", "en", "LLL"},
153         {UDAT_MONTH, "MMMM", "en", "LLLL"},
154         {UDAT_YEAR_NUM_MONTH, "yM","en","M/y"},
155         {UDAT_YEAR_ABBR_MONTH, "yMMM","en","MMM y"},
156         {UDAT_YEAR_MONTH, "yMMMM","en","MMMM y"},
157 
158         {UDAT_DAY, "d","en","d"},
159         {UDAT_YEAR_NUM_MONTH_DAY, "yMd", "en", "M/d/y"},
160         {UDAT_YEAR_ABBR_MONTH_DAY, "yMMMd", "en", "MMM d, y"},
161         {UDAT_YEAR_MONTH_DAY, "yMMMMd", "en", "MMMM d, y"},
162         {UDAT_YEAR_NUM_MONTH_WEEKDAY_DAY, "yMEd", "en", "EEE, M/d/y"},
163         {UDAT_YEAR_ABBR_MONTH_WEEKDAY_DAY, "yMMMEd", "en", "EEE, MMM d, y"},
164         {UDAT_YEAR_MONTH_WEEKDAY_DAY, "yMMMMEEEEd", "en", "EEEE, MMMM d, y"},
165 
166         {UDAT_NUM_MONTH_DAY, "Md","en","M/d"},
167         {UDAT_ABBR_MONTH_DAY, "MMMd","en","MMM d"},
168         {UDAT_MONTH_DAY, "MMMMd","en","MMMM d"},
169         {UDAT_NUM_MONTH_WEEKDAY_DAY, "MEd","en","EEE, M/d"},
170         {UDAT_ABBR_MONTH_WEEKDAY_DAY, "MMMEd","en","EEE, MMM d"},
171         {UDAT_MONTH_WEEKDAY_DAY, "MMMMEEEEd","en","EEEE, MMMM d"},
172 
173         {UDAT_HOUR, "j", "en", "h a"}, // (fixed expected result per ticket 6872<-6626)
174         {UDAT_HOUR24, "H", "en", "HH"}, // (fixed expected result per ticket 6872<-6626
175 
176         {UDAT_MINUTE, "m", "en", "m"},
177         {UDAT_HOUR_MINUTE, "jm","en","h:mm a"}, // (fixed expected result per ticket 6872<-7180)
178         {UDAT_HOUR24_MINUTE, "Hm", "en", "HH:mm"}, // (fixed expected result per ticket 6872<-6626)
179 
180         {UDAT_SECOND, "s", "en", "s"},
181         {UDAT_HOUR_MINUTE_SECOND, "jms","en","h:mm:ss a"}, // (fixed expected result per ticket 6872<-7180)
182         {UDAT_HOUR24_MINUTE_SECOND, "Hms","en","HH:mm:ss"}, // (fixed expected result per ticket 6872<-6626)
183         {UDAT_MINUTE_SECOND, "ms", "en", "mm:ss"}, // (fixed expected result per ticket 6872<-6626)
184 
185         {UDAT_LOCATION_TZ, "VVVV", "en", "VVVV"},
186         {UDAT_GENERIC_TZ, "vvvv", "en", "vvvv"},
187         {UDAT_ABBR_GENERIC_TZ, "v", "en", "v"},
188         {UDAT_SPECIFIC_TZ, "zzzz", "en", "zzzz"},
189         {UDAT_ABBR_SPECIFIC_TZ, "z", "en", "z"},
190         {UDAT_ABBR_UTC_TZ, "ZZZZ", "en", "ZZZZ"},
191 
192         {UDAT_YEAR_NUM_MONTH_DAY UDAT_ABBR_UTC_TZ, "yMdZZZZ", "en", "M/d/y, ZZZZ"},
193         {UDAT_MONTH_DAY UDAT_LOCATION_TZ, "MMMMdVVVV", "en", "MMMM d, VVVV"}
194     };
195 
196     IcuTestErrorCode errorCode(*this, "TestPatterns()");
197     for (int32_t i = 0; i < UPRV_LENGTHOF(EXPECTED); i++) {
198         // Verify that patterns have the correct values
199         UnicodeString actualPattern(EXPECTED[i].actualPattern, -1, US_INV);
200         UnicodeString expectedPattern(EXPECTED[i].expectedPattern, -1, US_INV);
201         Locale locale(EXPECTED[i].localeID);
202         if (actualPattern != expectedPattern) {
203             errln("FAILURE! Expected pattern: " + expectedPattern +
204                     " but was: " + actualPattern);
205         }
206 
207         // Verify that DataFormat instances produced contain the correct
208         // localized patterns
209         // TODO: use DateFormat::getInstanceForSkeleton(), ticket #9029
210         // Java test code:
211         // DateFormat date1 = DateFormat.getPatternInstance(actualPattern,
212         //         locale);
213         // DateFormat date2 = DateFormat.getPatternInstance(Calendar.getInstance(locale),
214         //         actualPattern, locale);
215         LocalPointer<DateTimePatternGenerator> generator(
216                 DateTimePatternGenerator::createInstance(locale, errorCode));
217         if(errorCode.errDataIfFailureAndReset("DateTimePatternGenerator::createInstance() failed for locale ID \"%s\"", EXPECTED[i].localeID)) {
218             continue;
219         }
220         UnicodeString pattern = generator->getBestPattern(actualPattern, errorCode);
221         SimpleDateFormat date1(pattern, locale, errorCode);
222         SimpleDateFormat date2(pattern, locale, errorCode);
223         date2.adoptCalendar(Calendar::createInstance(locale, errorCode));
224         if(errorCode.errIfFailureAndReset("DateFormat::getInstanceForSkeleton() failed")) {
225             errln("  for actualPattern \"%s\" & locale ID \"%s\"",
226                   EXPECTED[i].actualPattern, EXPECTED[i].localeID);
227             continue;
228         }
229 
230         UnicodeString expectedLocalPattern(EXPECTED[i].expectedLocalPattern, -1, US_INV);
231         UnicodeString actualLocalPattern1;
232         UnicodeString actualLocalPattern2;
233         date1.toLocalizedPattern(actualLocalPattern1, errorCode);
234         date2.toLocalizedPattern(actualLocalPattern2, errorCode);
235         if (actualLocalPattern1 != expectedLocalPattern) {
236             errln("FAILURE! Expected local pattern: " + expectedLocalPattern
237                     + " but was: " + actualLocalPattern1);
238         }
239         if (actualLocalPattern2 != expectedLocalPattern) {
240             errln("FAILURE! Expected local pattern: " + expectedLocalPattern
241                     + " but was: " + actualLocalPattern2);
242         }
243     }
244 }
245 
246 // Test written by Wally Wedel and emailed to me.
TestWallyWedel()247 void DateFormatTest::TestWallyWedel()
248 {
249     UErrorCode status = U_ZERO_ERROR;
250     /*
251      * Instantiate a TimeZone so we can get the ids.
252      */
253     TimeZone *tz = new SimpleTimeZone(7,"");
254     /*
255      * Computational variables.
256      */
257     int32_t offset, hours, minutes, seconds;
258     /*
259      * Instantiate a SimpleDateFormat set up to produce a full time
260      zone name.
261      */
262     SimpleDateFormat *sdf = new SimpleDateFormat((UnicodeString)"zzzz", status);
263     /*
264      * A String array for the time zone ids.
265      */
266     int32_t ids_length;
267     StringEnumeration* ids = TimeZone::createEnumeration();
268     if (ids == NULL) {
269         dataerrln("Unable to create TimeZone enumeration.");
270         if (sdf != NULL) {
271             delete sdf;
272         }
273         return;
274     }
275     ids_length = ids->count(status);
276     /*
277      * How many ids do we have?
278      */
279     logln("Time Zone IDs size: %d", ids_length);
280     /*
281      * Column headings (sort of)
282      */
283     logln("Ordinal ID offset(h:m) name");
284     /*
285      * Loop through the tzs.
286      */
287     UDate today = Calendar::getNow();
288     Calendar *cal = Calendar::createInstance(status);
289     for (int32_t i = 0; i < ids_length; i++) {
290         // logln(i + " " + ids[i]);
291         const UnicodeString* id = ids->snext(status);
292         TimeZone *ttz = TimeZone::createTimeZone(*id);
293         // offset = ttz.getRawOffset();
294         cal->setTimeZone(*ttz);
295         cal->setTime(today, status);
296         offset = cal->get(UCAL_ZONE_OFFSET, status) + cal->get(UCAL_DST_OFFSET, status);
297         // logln(i + " " + ids[i] + " offset " + offset);
298         const char* sign = "+";
299         if (offset < 0) {
300             sign = "-";
301             offset = -offset;
302         }
303         hours = offset/3600000;
304         minutes = (offset%3600000)/60000;
305         seconds = (offset%60000)/1000;
306         UnicodeString dstOffset = (UnicodeString)"" + sign + (hours < 10 ? "0" : "") +
307             (int32_t)hours + ":" + (minutes < 10 ? "0" : "") + (int32_t)minutes;
308         if (seconds != 0) {
309             dstOffset = dstOffset + ":" + (seconds < 10 ? "0" : "") + seconds;
310         }
311         /*
312          * Instantiate a date so we can display the time zone name.
313          */
314         sdf->setTimeZone(*ttz);
315         /*
316          * Format the output.
317          */
318         UnicodeString fmtOffset;
319         FieldPosition pos(FieldPosition::DONT_CARE);
320         sdf->format(today,fmtOffset, pos);
321         // UnicodeString fmtOffset = tzS.toString();
322         UnicodeString *fmtDstOffset = 0;
323         if (fmtOffset.startsWith("GMT") && fmtOffset.length() != 3)
324         {
325             //fmtDstOffset = fmtOffset->substring(3);
326             fmtDstOffset = new UnicodeString();
327             fmtOffset.extract(3, fmtOffset.length(), *fmtDstOffset);
328         }
329         /*
330          * Show our result.
331          */
332         UBool ok = fmtDstOffset == 0 || *fmtDstOffset == dstOffset;
333         if (ok)
334         {
335             logln(UnicodeString() + i + " " + *id + " " + dstOffset +
336                   " " + fmtOffset +
337                   (fmtDstOffset != 0 ? " ok" : " ?"));
338         }
339         else
340         {
341             errln(UnicodeString() + i + " " + *id + " " + dstOffset +
342                   " " + fmtOffset + " *** FAIL ***");
343         }
344         delete ttz;
345         delete fmtDstOffset;
346     }
347     delete cal;
348     //  delete ids;   // TODO:  BAD API
349     delete ids;
350     delete sdf;
351     delete tz;
352 }
353 
354 // -------------------------------------
355 
356 /**
357  * Test operator==
358  */
359 void
TestEquals()360 DateFormatTest::TestEquals()
361 {
362     DateFormat* fmtA = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::FULL);
363     DateFormat* fmtB = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::FULL);
364     if ( fmtA == NULL || fmtB == NULL){
365         dataerrln("Error calling DateFormat::createDateTimeInstance");
366         delete fmtA;
367         delete fmtB;
368         return;
369     }
370 
371     if (!(*fmtA == *fmtB)) errln((UnicodeString)"FAIL");
372     delete fmtA;
373     delete fmtB;
374 
375     TimeZone* test = TimeZone::createTimeZone("PDT");
376     delete test;
377 }
378 
379 // -------------------------------------
380 
381 /**
382  * Test the parsing of 2-digit years.
383  */
384 void
TestTwoDigitYearDSTParse(void)385 DateFormatTest::TestTwoDigitYearDSTParse(void)
386 {
387     UErrorCode status = U_ZERO_ERROR;
388     SimpleDateFormat fullFmt((UnicodeString)"EEE MMM dd HH:mm:ss.SSS zzz yyyy G", status);
389     SimpleDateFormat fmt((UnicodeString)"dd-MMM-yy h:mm:ss 'o''clock' a z", Locale::getEnglish(), status);
390     //DateFormat* fmt = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::FULL, Locale::ENGLISH);
391     UnicodeString s(u"03-Apr-04 2:20:47 o'clock AM PST");
392     LocalPointer<TimeZone> defaultTZ(TimeZone::createDefault());
393     LocalPointer<TimeZone> PST(TimeZone::createTimeZone("PST"));
394     int32_t defaultOffset = defaultTZ->getRawOffset();
395     int32_t PSTOffset = PST->getRawOffset();
396     int32_t hour = 2 + (defaultOffset - PSTOffset) / (60*60*1000);
397     // hour is the expected hour of day, in units of seconds
398     hour = ((hour < 0) ? hour + 24 : hour) * 60*60;
399 
400     UnicodeString str;
401 
402     if(U_FAILURE(status)) {
403         dataerrln("Could not set up test. exitting - %s", u_errorName(status));
404         return;
405     }
406 
407     UDate d = fmt.parse(s, status);
408     logln(s + " P> " + fullFmt.format(d, str));
409     int32_t y, m, day, hr, min, sec;
410     dateToFields(d, y, m, day, hr, min, sec);
411     hour += defaultTZ->inDaylightTime(d, status) ? 1 : 0;
412     hr = hr*60*60;
413     if (hr != hour)
414         errln((UnicodeString)"FAIL: Should parse to hour " + hour + " but got " + hr);
415 
416     if (U_FAILURE(status))
417         errln((UnicodeString)"FAIL: " + (int32_t)status);
418 }
419 
420 // -------------------------------------
421 
toHexString(int32_t i)422 UChar toHexString(int32_t i) { return (UChar)(i + (i < 10 ? 0x30 : (0x41 - 10))); }
423 
424 UnicodeString&
escape(UnicodeString & s)425 DateFormatTest::escape(UnicodeString& s)
426 {
427     UnicodeString buf;
428     for (int32_t i=0; i<s.length(); ++i)
429     {
430         UChar c = s[(int32_t)i];
431         if (c <= (UChar)0x7F) buf += c;
432         else {
433             buf += (UChar)0x5c; buf += (UChar)0x55;
434             buf += toHexString((c & 0xF000) >> 12);
435             buf += toHexString((c & 0x0F00) >> 8);
436             buf += toHexString((c & 0x00F0) >> 4);
437             buf += toHexString(c & 0x000F);
438         }
439     }
440     return (s = buf);
441 }
442 
443 // -------------------------------------
444 
445 /**
446  * This MUST be kept in sync with DateFormatSymbols.gPatternChars.
447  */
448 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
449 static const char* PATTERN_CHARS = "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB:";
450 #else
451 static const char* PATTERN_CHARS = "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB";
452 #endif
453 
454 /**
455  * A list of the names of all the fields in DateFormat.
456  * This MUST be kept in sync with DateFormat.
457  */
458 static const char* DATEFORMAT_FIELD_NAMES[] = {
459     "ERA_FIELD",
460     "YEAR_FIELD",
461     "MONTH_FIELD",
462     "DATE_FIELD",
463     "HOUR_OF_DAY1_FIELD",
464     "HOUR_OF_DAY0_FIELD",
465     "MINUTE_FIELD",
466     "SECOND_FIELD",
467     "MILLISECOND_FIELD",
468     "DAY_OF_WEEK_FIELD",
469     "DAY_OF_YEAR_FIELD",
470     "DAY_OF_WEEK_IN_MONTH_FIELD",
471     "WEEK_OF_YEAR_FIELD",
472     "WEEK_OF_MONTH_FIELD",
473     "AM_PM_FIELD",
474     "HOUR1_FIELD",
475     "HOUR0_FIELD",
476     "TIMEZONE_FIELD",
477     "YEAR_WOY_FIELD",
478     "DOW_LOCAL_FIELD",
479     "EXTENDED_YEAR_FIELD",
480     "JULIAN_DAY_FIELD",
481     "MILLISECONDS_IN_DAY_FIELD",
482     "TIMEZONE_RFC_FIELD",
483     "GENERIC_TIMEZONE_FIELD",
484     "STAND_ALONE_DAY_FIELD",
485     "STAND_ALONE_MONTH_FIELD",
486     "QUARTER_FIELD",
487     "STAND_ALONE_QUARTER_FIELD",
488     "TIMEZONE_SPECIAL_FIELD",
489     "YEAR_NAME_FIELD",
490     "TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD",
491     "TIMEZONE_ISO_FIELD",
492     "TIMEZONE_ISO_LOCAL_FIELD",
493     "RELATED_YEAR_FIELD",
494     "AM_PM_MIDNIGHT_NOON_FIELD",
495     "FLEXIBLE_DAY_PERIOD_FIELD",
496     "UDAT_TIME_SEPARATOR_FIELD",
497 };
498 
499 static const int32_t DATEFORMAT_FIELD_NAMES_LENGTH =
500     UPRV_LENGTHOF(DATEFORMAT_FIELD_NAMES);
501 
502 /**
503  * Verify that returned field position indices are correct.
504  */
TestFieldPosition()505 void DateFormatTest::TestFieldPosition() {
506     UErrorCode ec = U_ZERO_ERROR;
507     int32_t i, j, exp;
508     UnicodeString buf;
509 
510     // Verify data
511     DateFormatSymbols rootSyms(Locale(""), ec);
512     if (U_FAILURE(ec)) {
513         dataerrln("Unable to create DateFormatSymbols - %s", u_errorName(ec));
514         return;
515     }
516 
517     // local pattern chars data is not longer loaded
518     // from icu locale bundle
519     assertEquals("patternChars", PATTERN_CHARS, rootSyms.getLocalPatternChars(buf));
520     assertEquals("patternChars", PATTERN_CHARS, DateFormatSymbols::getPatternUChars());
521     assertTrue("DATEFORMAT_FIELD_NAMES", DATEFORMAT_FIELD_NAMES_LENGTH == UDAT_FIELD_COUNT);
522 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
523     assertTrue("Data", UDAT_FIELD_COUNT == uprv_strlen(PATTERN_CHARS));
524 #else
525     assertTrue("Data", UDAT_FIELD_COUNT == uprv_strlen(PATTERN_CHARS) + 1); // +1 for missing TIME_SEPARATOR pattern char
526 #endif
527 
528     // Create test formatters
529     const int32_t COUNT = 4;
530     DateFormat* dateFormats[COUNT];
531     dateFormats[0] = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale::getUS());
532     dateFormats[1] = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale::getFrance());
533     // Make the pattern "G y M d..."
534     buf.remove().append(PATTERN_CHARS);
535     for (j=buf.length()-1; j>=0; --j) buf.insert(j, (UChar)32/*' '*/);
536     dateFormats[2] = new SimpleDateFormat(buf, Locale::getUS(), ec);
537     // Make the pattern "GGGG yyyy MMMM dddd..."
538     for (j=buf.length()-1; j>=0; j-=2) {
539         for (i=0; i<3; ++i) {
540             buf.insert(j, buf.charAt(j));
541         }
542     }
543     dateFormats[3] = new SimpleDateFormat(buf, Locale::getUS(), ec);
544     if(U_FAILURE(ec)){
545         errln(UnicodeString("Could not create SimpleDateFormat object for locale en_US. Error: " )+ UnicodeString(u_errorName(ec)));
546         return;
547     }
548     UDate aug13 = 871508052513.0;
549 
550     // Expected output field values for above DateFormats on aug13
551     // Fields are given in order of DateFormat field number
552     const char* EXPECTED[] = {
553         "", "1997", "August", "13", "", "", "34", "12", "", "Wednesday",
554         "", "", "", "", "PM", "2", "", "Pacific Daylight Time", "", "",
555         "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
556 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
557         ":",
558 #else
559         "",
560 #endif
561 
562         "", "1997", "ao\\u00FBt", "13", "", "14", "34", "12", "", "mercredi",
563         "", "", "", "", "", "", "", "heure d\\u2019\\u00E9t\\u00E9 du Pacifique", "", "",
564         "", "", "", "", "",  "", "", "", "", "", "", "", "", "", "", "", "",
565 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
566         ":",
567 #else
568         "",
569 #endif
570 
571         "AD", "1997", "8", "13", "14", "14", "34", "12", "5", "Wed",
572         "225", "2", "33", "3", "PM", "2", "2", "PDT", "1997", "4",
573         "1997", "2450674", "52452513", "-0700", "PT",  "4", "8", "3", "3", "uslax",
574         "1997", "GMT-7", "-07", "-07", "1997", "PM", "in the afternoon",
575 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
576         ":",
577 #else
578         "",
579 #endif
580 
581         "Anno Domini", "1997", "August", "0013", "0014", "0014", "0034", "0012", "5130", "Wednesday",
582         "0225", "0002", "0033", "0003", "PM", "0002", "0002", "Pacific Daylight Time", "1997", "Wednesday",
583         "1997", "2450674", "52452513", "GMT-07:00", "Pacific Time",  "Wednesday", "August", "3rd quarter", "3rd quarter", "Los Angeles Time",
584         "1997", "GMT-07:00", "-0700", "-0700", "1997", "PM", "in the afternoon",
585 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
586         ":",
587 #else
588         "",
589 #endif
590     };
591 
592     const int32_t EXPECTED_LENGTH = UPRV_LENGTHOF(EXPECTED);
593 
594     assertTrue("data size", EXPECTED_LENGTH == COUNT * UDAT_FIELD_COUNT);
595 
596     TimeZone* PT = TimeZone::createTimeZone("America/Los_Angeles");
597     for (j = 0, exp = 0; j < COUNT; ++j) {
598         //  String str;
599         DateFormat* df = dateFormats[j];
600         df->setTimeZone(*PT);
601         SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(df);
602         if (sdtfmt != NULL) {
603             logln(" Pattern = " + sdtfmt->toPattern(buf.remove()));
604         } else {
605             logln(" Pattern = ? (not a SimpleDateFormat)");
606         }
607         logln((UnicodeString)"  Result = " + df->format(aug13, buf.remove()));
608 
609         int32_t expBase = exp; // save for later
610         for (i = 0; i < UDAT_FIELD_COUNT; ++i, ++exp) {
611             FieldPosition pos(i);
612             buf.remove();
613             df->format(aug13, buf, pos);
614             UnicodeString field;
615             buf.extractBetween(pos.getBeginIndex(), pos.getEndIndex(), field);
616             assertEquals((UnicodeString)"field #" + i + " " + DATEFORMAT_FIELD_NAMES[i],
617                          ctou(EXPECTED[exp]), field);
618         }
619 
620         // test FieldPositionIterator API
621         logln("FieldPositionIterator");
622         {
623           UErrorCode status = U_ZERO_ERROR;
624           FieldPositionIterator posIter;
625           FieldPosition fp;
626 
627           buf.remove();
628           df->format(aug13, buf, &posIter, status);
629           while (posIter.next(fp)) {
630             int32_t i = fp.getField();
631             UnicodeString field;
632             buf.extractBetween(fp.getBeginIndex(), fp.getEndIndex(), field);
633             assertEquals((UnicodeString)"field #" + i + " " + DATEFORMAT_FIELD_NAMES[i],
634                          ctou(EXPECTED[expBase + i]), field);
635           }
636 
637         }
638     }
639 
640 
641     // test null posIter
642     buf.remove();
643     UErrorCode status = U_ZERO_ERROR;
644     dateFormats[0]->format(aug13, buf, NULL, status);
645     // if we didn't crash, we succeeded.
646 
647     for (i=0; i<COUNT; ++i) {
648         delete dateFormats[i];
649     }
650     delete PT;
651 }
652 
653 // -------------------------------------
654 
655 /**
656  * General parse/format tests.  Add test cases as needed.
657  */
TestGeneral()658 void DateFormatTest::TestGeneral() {
659     const char* DATA[] = {
660         "yyyy MM dd HH:mm:ss.SSS",
661 
662         // Milliseconds are left-justified, since they format as fractions of a second
663         "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",
664         "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",
665         "y/M/d H:mm:ss.SSS", "F", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.567",
666         "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",
667     };
668     expect(DATA, UPRV_LENGTHOF(DATA), Locale("en", "", ""));
669 }
670 
671 // -------------------------------------
672 
673 /**
674  * Verify that strings which contain incomplete specifications are parsed
675  * correctly.  In some instances, this means not being parsed at all, and
676  * returning an appropriate error.
677  */
678 void
TestPartialParse994()679 DateFormatTest::TestPartialParse994()
680 {
681     UErrorCode status = U_ZERO_ERROR;
682     SimpleDateFormat* f = new SimpleDateFormat(status);
683     if (U_FAILURE(status)) {
684         dataerrln("Fail new SimpleDateFormat: %s", u_errorName(status));
685         delete f;
686         return;
687     }
688     UDate null = 0;
689     tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10:11:42", date(97, 1 - 1, 17, 10, 11, 42));
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 10", null);
692     tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 ", null);
693     tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17", null);
694     if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
695     delete f;
696 }
697 
698 // -------------------------------------
699 
700 void
tryPat994(SimpleDateFormat * format,const char * pat,const char * str,UDate expected)701 DateFormatTest::tryPat994(SimpleDateFormat* format, const char* pat, const char* str, UDate expected)
702 {
703     UErrorCode status = U_ZERO_ERROR;
704     UDate null = 0;
705     logln(UnicodeString("Pattern \"") + pat + "\"   String \"" + str + "\"");
706     //try {
707         format->applyPattern(pat);
708         UDate date = format->parse(str, status);
709         if (U_FAILURE(status) || date == null)
710         {
711             logln((UnicodeString)"ParseException: " + (int32_t)status);
712             if (expected != null) errln((UnicodeString)"FAIL: Expected " + dateToString(expected));
713         }
714         else
715         {
716             UnicodeString f;
717             ((DateFormat*)format)->format(date, f);
718             logln(UnicodeString(" parse(") + str + ") -> " + dateToString(date));
719             logln((UnicodeString)" format -> " + f);
720             if (expected == null ||
721                 !(date == expected)) errln((UnicodeString)"FAIL: Expected null");//" + expected);
722             if (!(f == str)) errln(UnicodeString("FAIL: Expected ") + str);
723         }
724     //}
725     //catch(ParseException e) {
726     //    logln((UnicodeString)"ParseException: " + e.getMessage());
727     //    if (expected != null) errln((UnicodeString)"FAIL: Expected " + dateToString(expected));
728     //}
729     //catch(Exception e) {
730     //    errln((UnicodeString)"*** Exception:");
731     //    e.printStackTrace();
732     //}
733 }
734 
735 // -------------------------------------
736 
737 /**
738  * Verify the behavior of patterns in which digits for different fields run together
739  * without intervening separators.
740  */
741 void
TestRunTogetherPattern985()742 DateFormatTest::TestRunTogetherPattern985()
743 {
744     UErrorCode status = U_ZERO_ERROR;
745     UnicodeString format("yyyyMMddHHmmssSSS");
746     UnicodeString now, then;
747     //UBool flag;
748     SimpleDateFormat *formatter = new SimpleDateFormat(format, status);
749     if (U_FAILURE(status)) {
750         dataerrln("Fail new SimpleDateFormat: %s", u_errorName(status));
751         delete formatter;
752         return;
753     }
754     UDate date1 = Calendar::getNow();
755     ((DateFormat*)formatter)->format(date1, now);
756     logln(now);
757     ParsePosition pos(0);
758     UDate date2 = formatter->parse(now, pos);
759     if (date2 == 0) then = UnicodeString("Parse stopped at ") + pos.getIndex();
760     else ((DateFormat*)formatter)->format(date2, then);
761     logln(then);
762     if (!(date2 == date1)) errln((UnicodeString)"FAIL");
763     delete formatter;
764     if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
765 }
766 
767 // -------------------------------------
768 
769 /**
770  * Verify the behavior of patterns in which digits for different fields run together
771  * without intervening separators.
772  */
773 void
TestRunTogetherPattern917()774 DateFormatTest::TestRunTogetherPattern917()
775 {
776     UErrorCode status = U_ZERO_ERROR;
777     SimpleDateFormat* fmt;
778     UnicodeString myDate;
779     fmt = new SimpleDateFormat((UnicodeString)"yyyy/MM/dd", status);
780     if (U_FAILURE(status)) {
781         dataerrln("Fail new SimpleDateFormat: %s", u_errorName(status));
782         delete fmt;
783         return;
784     }
785     myDate = "1997/02/03";
786     testIt917(fmt, myDate, date(97, 2 - 1, 3));
787     delete fmt;
788     fmt = new SimpleDateFormat((UnicodeString)"yyyyMMdd", status);
789     myDate = "19970304";
790     testIt917(fmt, myDate, date(97, 3 - 1, 4));
791     delete fmt;
792     if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
793 }
794 
795 // -------------------------------------
796 
797 void
testIt917(SimpleDateFormat * fmt,UnicodeString & str,UDate expected)798 DateFormatTest::testIt917(SimpleDateFormat* fmt, UnicodeString& str, UDate expected)
799 {
800     UErrorCode status = U_ZERO_ERROR;
801     UnicodeString pattern;
802     logln((UnicodeString)"pattern=" + fmt->toPattern(pattern) + "   string=" + str);
803     Formattable o;
804     //try {
805         ((Format*)fmt)->parseObject(str, o, status);
806     //}
807     if (U_FAILURE(status)) return;
808     //catch(ParseException e) {
809     //    e.printStackTrace();
810     //    return;
811     //}
812     logln((UnicodeString)"Parsed object: " + dateToString(o.getDate()));
813     if (!(o.getDate() == expected)) errln((UnicodeString)"FAIL: Expected " + dateToString(expected));
814     UnicodeString formatted; ((Format*)fmt)->format(o, formatted, status);
815     logln((UnicodeString)"Formatted string: " + formatted);
816     if (!(formatted == str)) errln((UnicodeString)"FAIL: Expected " + str);
817     if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
818 }
819 
820 // -------------------------------------
821 
822 /**
823  * Verify the handling of Czech June and July, which have the unique attribute that
824  * one is a proper prefix substring of the other.
825  */
826 void
TestCzechMonths459()827 DateFormatTest::TestCzechMonths459()
828 {
829     UErrorCode status = U_ZERO_ERROR;
830     DateFormat* fmt = DateFormat::createDateInstance(DateFormat::FULL, Locale("cs", "", ""));
831     if (fmt == NULL){
832         dataerrln("Error calling DateFormat::createDateInstance()");
833         return;
834     }
835 
836     UnicodeString pattern;
837     logln((UnicodeString)"Pattern " + ((SimpleDateFormat*) fmt)->toPattern(pattern));
838     UDate june = date(97, UCAL_JUNE, 15);
839     UDate july = date(97, UCAL_JULY, 15);
840     UnicodeString juneStr; fmt->format(june, juneStr);
841     UnicodeString julyStr; fmt->format(july, julyStr);
842     //try {
843         logln((UnicodeString)"format(June 15 1997) = " + juneStr);
844         UDate d = fmt->parse(juneStr, status);
845         UnicodeString s; fmt->format(d, s);
846         int32_t month,yr,day,hr,min,sec; dateToFields(d,yr,month,day,hr,min,sec);
847         logln((UnicodeString)"  -> parse -> " + s + " (month = " + month + ")");
848         if (month != UCAL_JUNE) errln((UnicodeString)"FAIL: Month should be June");
849         logln((UnicodeString)"format(July 15 1997) = " + julyStr);
850         d = fmt->parse(julyStr, status);
851         fmt->format(d, s);
852         dateToFields(d,yr,month,day,hr,min,sec);
853         logln((UnicodeString)"  -> parse -> " + s + " (month = " + month + ")");
854         if (month != UCAL_JULY) errln((UnicodeString)"FAIL: Month should be July");
855     //}
856     //catch(ParseException e) {
857     if (U_FAILURE(status))
858         errln((UnicodeString)"Exception: " + (int32_t)status);
859     //}
860     delete fmt;
861 }
862 
863 // -------------------------------------
864 
865 /**
866  * Test the handling of 'D' in patterns.
867  */
868 void
TestLetterDPattern212()869 DateFormatTest::TestLetterDPattern212()
870 {
871     UErrorCode status = U_ZERO_ERROR;
872     UnicodeString dateString("1995-040.05:01:29");
873     UnicodeString bigD("yyyy-DDD.hh:mm:ss");
874     UnicodeString littleD("yyyy-ddd.hh:mm:ss");
875     UDate expLittleD = date(95, 0, 1, 5, 1, 29);
876     UDate expBigD = expLittleD + 39 * 24 * 3600000.0;
877     expLittleD = expBigD; // Expect the same, with default lenient parsing
878     logln((UnicodeString)"dateString= " + dateString);
879     SimpleDateFormat *formatter = new SimpleDateFormat(bigD, status);
880     if (U_FAILURE(status)) {
881         dataerrln("Fail new SimpleDateFormat: %s", u_errorName(status));
882         delete formatter;
883         return;
884     }
885     ParsePosition pos(0);
886     UDate myDate = formatter->parse(dateString, pos);
887     logln((UnicodeString)"Using " + bigD + " -> " + myDate);
888     if (myDate != expBigD) errln((UnicodeString)"FAIL: bigD - Expected " + dateToString(expBigD));
889     delete formatter;
890     formatter = new SimpleDateFormat(littleD, status);
891     ASSERT_OK(status);
892     pos = ParsePosition(0);
893     myDate = formatter->parse(dateString, pos);
894     logln((UnicodeString)"Using " + littleD + " -> " + dateToString(myDate));
895     if (myDate != expLittleD) errln((UnicodeString)"FAIL: littleD - Expected " + dateToString(expLittleD));
896     delete formatter;
897     if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
898 }
899 
900 // -------------------------------------
901 
902 /**
903  * Test the day of year pattern.
904  */
905 void
TestDayOfYearPattern195()906 DateFormatTest::TestDayOfYearPattern195()
907 {
908     UErrorCode status = U_ZERO_ERROR;
909     UDate today = Calendar::getNow();
910     int32_t year,month,day,hour,min,sec; dateToFields(today,year,month,day,hour,min,sec);
911     UDate expected = date(year, month, day);
912     logln((UnicodeString)"Test Date: " + dateToString(today));
913     SimpleDateFormat* sdf = (SimpleDateFormat*)DateFormat::createDateInstance();
914     if (sdf == NULL){
915         dataerrln("Error calling DateFormat::createDateInstance()");
916         return;
917     }
918     tryPattern(*sdf, today, 0, expected);
919     tryPattern(*sdf, today, "G yyyy DDD", expected);
920     delete sdf;
921     if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
922 }
923 
924 // -------------------------------------
925 
926 void
tryPattern(SimpleDateFormat & sdf,UDate d,const char * pattern,UDate expected)927 DateFormatTest::tryPattern(SimpleDateFormat& sdf, UDate d, const char* pattern, UDate expected)
928 {
929     UErrorCode status = U_ZERO_ERROR;
930     if (pattern != 0) sdf.applyPattern(pattern);
931     UnicodeString thePat;
932     logln((UnicodeString)"pattern: " + sdf.toPattern(thePat));
933     UnicodeString formatResult; (*(DateFormat*)&sdf).format(d, formatResult);
934     logln((UnicodeString)" format -> " + formatResult);
935     // try {
936         UDate d2 = sdf.parse(formatResult, status);
937         logln((UnicodeString)" parse(" + formatResult + ") -> " + dateToString(d2));
938         if (d2 != expected) errln((UnicodeString)"FAIL: Expected " + dateToString(expected));
939         UnicodeString format2; (*(DateFormat*)&sdf).format(d2, format2);
940         logln((UnicodeString)" format -> " + format2);
941         if (!(formatResult == format2)) errln((UnicodeString)"FAIL: Round trip drift");
942     //}
943     //catch(Exception e) {
944     if (U_FAILURE(status))
945         errln((UnicodeString)"Error: " + (int32_t)status);
946     //}
947 }
948 
949 // -------------------------------------
950 
951 /**
952  * Test the handling of single quotes in patterns.
953  */
954 void
TestQuotePattern161()955 DateFormatTest::TestQuotePattern161()
956 {
957     UErrorCode status = U_ZERO_ERROR;
958     SimpleDateFormat* formatter = new SimpleDateFormat((UnicodeString)"MM/dd/yyyy 'at' hh:mm:ss a zzz", status);
959     if (U_FAILURE(status)) {
960         dataerrln("Fail new SimpleDateFormat: %s", u_errorName(status));
961         delete formatter;
962         return;
963     }
964     UDate currentTime_1 = date(97, UCAL_AUGUST, 13, 10, 42, 28);
965     UnicodeString dateString; ((DateFormat*)formatter)->format(currentTime_1, dateString);
966     UnicodeString exp("08/13/1997 at 10:42:28 AM ");
967     logln((UnicodeString)"format(" + dateToString(currentTime_1) + ") = " + dateString);
968     if (0 != dateString.compareBetween(0, exp.length(), exp, 0, exp.length())) errln((UnicodeString)"FAIL: Expected " + exp);
969     delete formatter;
970     if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
971 }
972 
973 // -------------------------------------
974 
975 /**
976  * Verify the correct behavior when handling invalid input strings.
977  */
978 void
TestBadInput135()979 DateFormatTest::TestBadInput135()
980 {
981     UErrorCode status = U_ZERO_ERROR;
982     DateFormat::EStyle looks[] = {
983         DateFormat::SHORT, DateFormat::MEDIUM, DateFormat::LONG, DateFormat::FULL
984     };
985     int32_t looks_length = UPRV_LENGTHOF(looks);
986     const char* strings[] = {
987         "Mar 15", "Mar 15 1997", "asdf", "3/1/97 1:23:", "3/1/00 1:23:45 AM"
988     };
989     int32_t strings_length = UPRV_LENGTHOF(strings);
990     DateFormat *full = DateFormat::createDateTimeInstance(DateFormat::LONG, DateFormat::LONG);
991     if(full==NULL) {
992       dataerrln("could not create date time instance");
993       return;
994     }
995     UnicodeString expected("March 1, 2000 at 1:23:45 AM ");
996     for (int32_t i = 0; i < strings_length;++i) {
997         const char* text = strings[i];
998         for (int32_t j = 0; j < looks_length;++j) {
999             DateFormat::EStyle dateLook = looks[j];
1000             for (int32_t k = 0; k < looks_length;++k) {
1001                 DateFormat::EStyle timeLook = looks[k];
1002                 DateFormat *df = DateFormat::createDateTimeInstance(dateLook, timeLook);
1003                 if (df == NULL){
1004                     dataerrln("Error calling DateFormat::createDateTimeInstance()");
1005                     continue;
1006                 }
1007                 UnicodeString prefix = UnicodeString(text) + ", " + dateLook + "/" + timeLook + ": ";
1008                 //try {
1009                     UDate when = df->parse(text, status);
1010                     if (when == 0 && U_SUCCESS(status)) {
1011                         errln(prefix + "SHOULD NOT HAPPEN: parse returned 0.");
1012                         continue;
1013                     }
1014                     if (U_SUCCESS(status))
1015                     {
1016                         UnicodeString format;
1017                         UnicodeString pattern;
1018                         SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(df);
1019                         if (sdtfmt != NULL) {
1020                             sdtfmt->toPattern(pattern);
1021                         }
1022                         full->format(when, format);
1023                         logln(prefix + "OK: " + format);
1024                         if (0!=format.compareBetween(0, expected.length(), expected, 0, expected.length()))
1025                             errln((UnicodeString)"FAIL: Parse \"" + text + "\", pattern \"" + pattern + "\", expected " + expected + " got " + format);
1026                     }
1027                 //}
1028                 //catch(ParseException e) {
1029                     else
1030                         status = U_ZERO_ERROR;
1031                 //}
1032                 //catch(StringIndexOutOfBoundsException e) {
1033                 //    errln(prefix + "SHOULD NOT HAPPEN: " + (int)status);
1034                 //}
1035                 delete df;
1036             }
1037         }
1038     }
1039     delete full;
1040     if (U_FAILURE(status))
1041         errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
1042 }
1043 
1044 static const char* const parseFormats[] = {
1045     "MMMM d, yyyy",
1046     "MMMM d yyyy",
1047     "M/d/yy",
1048     "d MMMM, yyyy",
1049     "d MMMM yyyy",
1050     "d MMMM",
1051     "MMMM d",
1052     "yyyy",
1053     "h:mm a MMMM d, yyyy"
1054 };
1055 
1056 #if 0
1057 // strict inputStrings
1058 static const char* const inputStrings[] = {
1059     "bogus string", 0, 0, 0, 0, 0, 0, 0, 0, 0,
1060     "April 1, 1997", "April 1, 1997", 0, 0, 0, 0, 0, "April 1", 0, 0,
1061     "Jan 1, 1970", "January 1, 1970", 0, 0, 0, 0, 0, "January 1", 0, 0,
1062     "Jan 1 2037", 0, "January 1 2037", 0, 0, 0, 0, "January 1", 0, 0,
1063     "1/1/70", 0, 0, "1/1/70", 0, 0, 0, 0, "0001", 0,
1064     "5 May 1997", 0, 0, 0, 0, "5 May 1997", "5 May", 0, "0005", 0,
1065     "16 May", 0, 0, 0, 0, 0, "16 May", 0, "0016", 0,
1066     "April 30", 0, 0, 0, 0, 0, 0, "April 30", 0, 0,
1067     "1998", 0, 0, 0, 0, 0, 0, 0, "1998", 0,
1068     "1", 0, 0, 0, 0, 0, 0, 0, "0001", 0,
1069     "3:00 pm Jan 1, 1997", 0, 0, 0, 0, 0, 0, 0, "0003", "3:00 PM January 1, 1997",
1070 };
1071 #else
1072 // lenient inputStrings
1073 static const char* const inputStrings[] = {
1074     "bogus string", 0, 0, 0, 0, 0, 0, 0, 0, 0,
1075     "April 1, 1997", "April 1, 1997", "April 1 1997", "4/1/97", 0, 0, 0, "April 1", 0, 0,
1076     "Jan 1, 1970", "January 1, 1970", "January 1 1970", "1/1/70", 0, 0, 0, "January 1", 0, 0,
1077     "Jan 1 2037", "January 1, 2037", "January 1 2037", "1/1/37", 0, 0, 0, "January 1", 0, 0,
1078     "1/1/70", "January 1, 0070", "January 1 0070", "1/1/70", "1 January, 0070", "1 January 0070", "1 January", "January 1", "0001", 0,
1079     "5 May 1997", 0, 0, 0, "5 May, 1997", "5 May 1997", "5 May", 0, "0005", 0,
1080     "16 May", 0, 0, 0, 0, 0, "16 May", 0, "0016", 0,
1081     "April 30", 0, 0, 0, 0, 0, 0, "April 30", 0, 0,
1082     "1998", 0, 0, 0, 0, 0, 0, 0, "1998", 0,
1083     "1", 0, 0, 0, 0, 0, 0, 0, "0001", 0,
1084     "3:00 pm Jan 1, 1997", 0, 0, 0, 0, 0, 0, 0, "0003", "3:00 PM January 1, 1997",
1085 };
1086 #endif
1087 
1088 // -------------------------------------
1089 
1090 /**
1091  * Verify the correct behavior when parsing an array of inputs against an
1092  * array of patterns, with known results.  The results are encoded after
1093  * the input strings in each row.
1094  */
1095 void
TestBadInput135a()1096 DateFormatTest::TestBadInput135a()
1097 {
1098   UErrorCode status = U_ZERO_ERROR;
1099   SimpleDateFormat* dateParse = new SimpleDateFormat(status);
1100   if(U_FAILURE(status)) {
1101     dataerrln("Failed creating SimpleDateFormat with %s. Quitting test", u_errorName(status));
1102     delete dateParse;
1103     return;
1104   }
1105   const char* s;
1106   UDate date;
1107   const uint32_t PF_LENGTH = UPRV_LENGTHOF(parseFormats);
1108   const uint32_t INPUT_LENGTH = UPRV_LENGTHOF(inputStrings);
1109 
1110   dateParse->applyPattern("d MMMM, yyyy");
1111   dateParse->adoptTimeZone(TimeZone::createDefault());
1112   s = "not parseable";
1113   UnicodeString thePat;
1114   logln(UnicodeString("Trying to parse \"") + s + "\" with " + dateParse->toPattern(thePat));
1115   //try {
1116   date = dateParse->parse(s, status);
1117   if (U_SUCCESS(status))
1118     errln((UnicodeString)"FAIL: Expected exception during parse");
1119   //}
1120   //catch(Exception ex) {
1121   else
1122     logln((UnicodeString)"Exception during parse: " + (int32_t)status);
1123   status = U_ZERO_ERROR;
1124   //}
1125   for (uint32_t i = 0; i < INPUT_LENGTH; i += (PF_LENGTH + 1)) {
1126     ParsePosition parsePosition(0);
1127     UnicodeString s( inputStrings[i]);
1128     for (uint32_t index = 0; index < PF_LENGTH;++index) {
1129       const char* expected = inputStrings[i + 1 + index];
1130       dateParse->applyPattern(parseFormats[index]);
1131       dateParse->adoptTimeZone(TimeZone::createDefault());
1132       //try {
1133       parsePosition.setIndex(0);
1134       date = dateParse->parse(s, parsePosition);
1135       if (parsePosition.getIndex() != 0) {
1136         UnicodeString s1, s2;
1137         s.extract(0, parsePosition.getIndex(), s1);
1138         s.extract(parsePosition.getIndex(), s.length(), s2);
1139         if (date == 0) {
1140           errln((UnicodeString)"ERROR: null result fmt=\"" +
1141                      parseFormats[index] +
1142                      "\" pos=" + parsePosition.getIndex() + " " +
1143                      s1 + "|" + s2);
1144         }
1145         else {
1146           UnicodeString result;
1147           ((DateFormat*)dateParse)->format(date, result);
1148           logln((UnicodeString)"Parsed \"" + s + "\" using \"" + dateParse->toPattern(thePat) + "\" to: " + result);
1149           if (expected == 0)
1150             errln((UnicodeString)"FAIL: Expected parse failure, got " + result);
1151           else if (!(result == expected))
1152             errln(UnicodeString("FAIL: Parse \"") + s + UnicodeString("\", expected ") + expected + UnicodeString(", got ") + result);
1153         }
1154       }
1155       else if (expected != 0) {
1156         errln(UnicodeString("FAIL: Expected ") + expected + " from \"" +
1157                      s + "\" with \"" + dateParse->toPattern(thePat) + "\"");
1158       }
1159       //}
1160       //catch(Exception ex) {
1161       if (U_FAILURE(status))
1162         errln((UnicodeString)"An exception was thrown during parse: " + (int32_t)status);
1163       //}
1164     }
1165   }
1166   delete dateParse;
1167   if (U_FAILURE(status))
1168     errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
1169 }
1170 
1171 // -------------------------------------
1172 
1173 /**
1174  * Test the parsing of two-digit years.
1175  */
1176 void
TestTwoDigitYear()1177 DateFormatTest::TestTwoDigitYear()
1178 {
1179     UErrorCode ec = U_ZERO_ERROR;
1180     SimpleDateFormat fmt("dd/MM/yy", Locale::getUK(), ec);
1181     if (U_FAILURE(ec)) {
1182         dataerrln("FAIL: SimpleDateFormat constructor - %s", u_errorName(ec));
1183         return;
1184     }
1185     parse2DigitYear(fmt, "5/6/30", date(130, UCAL_JUNE, 5));
1186     parse2DigitYear(fmt, "4/6/50", date(50, UCAL_JUNE, 4));
1187 }
1188 
1189 // -------------------------------------
1190 
1191 void
parse2DigitYear(DateFormat & fmt,const char * str,UDate expected)1192 DateFormatTest::parse2DigitYear(DateFormat& fmt, const char* str, UDate expected)
1193 {
1194     UErrorCode status = U_ZERO_ERROR;
1195     //try {
1196         UDate d = fmt.parse(str, status);
1197         UnicodeString thePat;
1198         logln(UnicodeString("Parsing \"") + str + "\" with " + ((SimpleDateFormat*)&fmt)->toPattern(thePat) +
1199             "  => " + dateToString(d));
1200         if (d != expected) errln((UnicodeString)"FAIL: Expected " + expected);
1201     //}
1202     //catch(ParseException e) {
1203         if (U_FAILURE(status))
1204         errln((UnicodeString)"FAIL: Got exception");
1205     //}
1206 }
1207 
1208 // -------------------------------------
1209 
1210 /**
1211  * Test the formatting of time zones.
1212  */
1213 void
TestDateFormatZone061()1214 DateFormatTest::TestDateFormatZone061()
1215 {
1216     UErrorCode status = U_ZERO_ERROR;
1217     UDate date;
1218     DateFormat *formatter;
1219     date= 859248000000.0;
1220     logln((UnicodeString)"Date 1997/3/25 00:00 GMT: " + date);
1221     formatter = new SimpleDateFormat((UnicodeString)"dd-MMM-yyyyy HH:mm", Locale::getUK(), status);
1222     if(U_FAILURE(status)) {
1223       dataerrln("Failed creating SimpleDateFormat with %s. Quitting test", u_errorName(status));
1224       delete formatter;
1225       return;
1226     }
1227     formatter->adoptTimeZone(TimeZone::createTimeZone("GMT"));
1228     UnicodeString temp; formatter->format(date, temp);
1229     logln((UnicodeString)"Formatted in GMT to: " + temp);
1230     //try {
1231         UDate tempDate = formatter->parse(temp, status);
1232         logln((UnicodeString)"Parsed to: " + dateToString(tempDate));
1233         if (tempDate != date) errln((UnicodeString)"FAIL: Expected " + dateToString(date));
1234     //}
1235     //catch(Throwable t) {
1236     if (U_FAILURE(status))
1237         errln((UnicodeString)"Date Formatter throws: " + (int32_t)status);
1238     //}
1239     delete formatter;
1240 }
1241 
1242 // -------------------------------------
1243 
1244 /**
1245  * Test the formatting of time zones.
1246  */
1247 void
TestDateFormatZone146()1248 DateFormatTest::TestDateFormatZone146()
1249 {
1250     TimeZone *saveDefault = TimeZone::createDefault();
1251 
1252         //try {
1253     TimeZone *thedefault = TimeZone::createTimeZone("GMT");
1254     TimeZone::setDefault(*thedefault);
1255             // java.util.Locale.setDefault(new java.util.Locale("ar", "", ""));
1256 
1257             // check to be sure... its GMT all right
1258         TimeZone *testdefault = TimeZone::createDefault();
1259         UnicodeString testtimezone;
1260         testdefault->getID(testtimezone);
1261         if (testtimezone == "GMT")
1262             logln("Test timezone = " + testtimezone);
1263         else
1264             dataerrln("Test timezone should be GMT, not " + testtimezone);
1265 
1266         UErrorCode status = U_ZERO_ERROR;
1267         // now try to use the default GMT time zone
1268         GregorianCalendar *greenwichcalendar =
1269             new GregorianCalendar(1997, 3, 4, 23, 0, status);
1270         if (U_FAILURE(status)) {
1271             dataerrln("Fail new GregorianCalendar: %s", u_errorName(status));
1272         } else {
1273             //*****************************greenwichcalendar.setTimeZone(TimeZone.getDefault());
1274             //greenwichcalendar.set(1997, 3, 4, 23, 0);
1275             // try anything to set hour to 23:00 !!!
1276             greenwichcalendar->set(UCAL_HOUR_OF_DAY, 23);
1277             // get time
1278             UDate greenwichdate = greenwichcalendar->getTime(status);
1279             // format every way
1280             UnicodeString DATA [] = {
1281                 UnicodeString("simple format:  "), UnicodeString("04/04/97 23:00 GMT"),
1282                     UnicodeString("MM/dd/yy HH:mm z"),
1283                 UnicodeString("full format:    "), UnicodeString("Friday, April 4, 1997 11:00:00 o'clock PM GMT"),
1284                     UnicodeString("EEEE, MMMM d, yyyy h:mm:ss 'o''clock' a z"),
1285                 UnicodeString("long format:    "), UnicodeString("April 4, 1997 11:00:00 PM GMT"),
1286                     UnicodeString("MMMM d, yyyy h:mm:ss a z"),
1287                 UnicodeString("default format: "), UnicodeString("04-Apr-97 11:00:00 PM"),
1288                     UnicodeString("dd-MMM-yy h:mm:ss a"),
1289                 UnicodeString("short format:   "), UnicodeString("4/4/97 11:00 PM"),
1290                     UnicodeString("M/d/yy h:mm a")
1291             };
1292             int32_t DATA_length = UPRV_LENGTHOF(DATA);
1293 
1294             for (int32_t i=0; i<DATA_length; i+=3) {
1295                 SimpleDateFormat fmt(DATA[i+2], Locale::getEnglish(), status);
1296                 if (U_FAILURE(status)) {
1297                     dataerrln("Unable to create SimpleDateFormat - %s", u_errorName(status));
1298                     break;
1299                 }
1300                 fmt.setCalendar(*greenwichcalendar);
1301                 UnicodeString result;
1302                 result = fmt.format(greenwichdate, result);
1303                 logln(DATA[i] + result);
1304                 if (result != DATA[i+1])
1305                     errln("FAIL: Expected " + DATA[i+1] + ", got " + result);
1306             }
1307         }
1308     //}
1309     //finally {
1310         TimeZone::adoptDefault(saveDefault);
1311     //}
1312         delete testdefault;
1313         delete greenwichcalendar;
1314         delete thedefault;
1315 
1316 
1317 }
1318 
1319 // -------------------------------------
1320 
1321 /**
1322  * Test the formatting of dates in different locales.
1323  */
1324 void
TestLocaleDateFormat()1325 DateFormatTest::TestLocaleDateFormat() // Bug 495
1326 {
1327     UDate testDate = date(97, UCAL_SEPTEMBER, 15);
1328     DateFormat *dfFrench = DateFormat::createDateTimeInstance(DateFormat::FULL,
1329         DateFormat::FULL, Locale::getFrench());
1330     DateFormat *dfUS = DateFormat::createDateTimeInstance(DateFormat::FULL,
1331         DateFormat::FULL, Locale::getUS());
1332     UnicodeString expectedFRENCH ( "lundi 15 septembre 1997 \\u00E0 00:00:00 heure d\\u2019\\u00E9t\\u00E9 du Pacifique", -1, US_INV );
1333     expectedFRENCH = expectedFRENCH.unescape();
1334     UnicodeString expectedUS ( "Monday, September 15, 1997 at 12:00:00 AM Pacific Daylight Time" );
1335     logln((UnicodeString)"Date set to : " + dateToString(testDate));
1336     UnicodeString out;
1337     if (dfUS == NULL || dfFrench == NULL){
1338         dataerrln("Error calling DateFormat::createDateTimeInstance)");
1339         delete dfUS;
1340         delete dfFrench;
1341         return;
1342     }
1343 
1344     dfFrench->format(testDate, out);
1345     logln((UnicodeString)"Date Formated with French Locale " + out);
1346     if (!(out == expectedFRENCH))
1347         errln((UnicodeString)"FAIL: Expected " + expectedFRENCH);
1348     out.truncate(0);
1349     dfUS->format(testDate, out);
1350     logln((UnicodeString)"Date Formated with US Locale " + out);
1351     if (!(out == expectedUS))
1352         errln((UnicodeString)"FAIL: Expected " + expectedUS);
1353     delete dfUS;
1354     delete dfFrench;
1355 }
1356 
1357 void
TestFormattingLocaleTimeSeparator()1358 DateFormatTest::TestFormattingLocaleTimeSeparator()
1359 {
1360     // This test not as useful as it once was, since timeSeparator
1361     // in the Arabic locale is changed back to ":" in CLDR 28.
1362     const UDate testDate = 874266720000.;  // Sun Sep 14 21:52:00 CET 1997
1363     logln((UnicodeString)"Date set to : " + dateToString(testDate));
1364 
1365     const LocalPointer<const TimeZone> tz(TimeZone::createTimeZone("CET"));
1366 
1367     const LocalPointer<DateFormat> dfArab(DateFormat::createTimeInstance(
1368             DateFormat::SHORT, Locale("ar", "EG")));
1369 
1370     const LocalPointer<DateFormat> dfLatn(DateFormat::createTimeInstance(
1371             DateFormat::SHORT, Locale("ar", "EG", NULL, "numbers=latn")));
1372 
1373     if (dfLatn.isNull() || dfArab.isNull()) {
1374         dataerrln("Error calling DateFormat::createTimeInstance()");
1375         return;
1376     }
1377 
1378     dfArab->setTimeZone(*tz);
1379     dfLatn->setTimeZone(*tz);
1380 
1381     const UnicodeString expectedArab = UnicodeString(
1382             "\\u0669:\\u0665\\u0662 \\u0645", -1, US_INV).unescape();
1383 
1384     const UnicodeString expectedLatn = UnicodeString(
1385             "9:52 \\u0645", -1, US_INV).unescape();
1386 
1387     UnicodeString actualArab;
1388     UnicodeString actualLatn;
1389 
1390     dfArab->format(testDate, actualArab);
1391     dfLatn->format(testDate, actualLatn);
1392 
1393     assertEquals("Arab", expectedArab, actualArab);
1394     assertEquals("Latn", expectedLatn, actualLatn);
1395 }
1396 
1397 /**
1398  * Test DateFormat(Calendar) API
1399  */
TestDateFormatCalendar()1400 void DateFormatTest::TestDateFormatCalendar() {
1401     DateFormat *date=0, *time=0, *full=0;
1402     Calendar *cal=0;
1403     UnicodeString str;
1404     ParsePosition pos;
1405     UDate when;
1406     UErrorCode ec = U_ZERO_ERROR;
1407 
1408     /* Create a formatter for date fields. */
1409     date = DateFormat::createDateInstance(DateFormat::kShort, Locale::getUS());
1410     if (date == NULL) {
1411         dataerrln("FAIL: createDateInstance failed");
1412         goto FAIL;
1413     }
1414 
1415     /* Create a formatter for time fields. */
1416     time = DateFormat::createTimeInstance(DateFormat::kShort, Locale::getUS());
1417     if (time == NULL) {
1418         errln("FAIL: createTimeInstance failed");
1419         goto FAIL;
1420     }
1421 
1422     /* Create a full format for output */
1423     full = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull,
1424                                               Locale::getUS());
1425     if (full == NULL) {
1426         errln("FAIL: createInstance failed");
1427         goto FAIL;
1428     }
1429 
1430     /* Create a calendar */
1431     cal = Calendar::createInstance(Locale::getUS(), ec);
1432     if (cal == NULL || U_FAILURE(ec)) {
1433         errln((UnicodeString)"FAIL: Calendar::createInstance failed with " +
1434               u_errorName(ec));
1435         goto FAIL;
1436     }
1437 
1438     /* Parse the date */
1439     cal->clear();
1440     str = UnicodeString("4/5/2001", "");
1441     pos.setIndex(0);
1442     date->parse(str, *cal, pos);
1443     if (pos.getIndex() != str.length()) {
1444         errln((UnicodeString)"FAIL: DateFormat::parse(4/5/2001) failed at " +
1445               pos.getIndex());
1446         goto FAIL;
1447     }
1448 
1449     /* Parse the time */
1450     str = UnicodeString("5:45 PM", "");
1451     pos.setIndex(0);
1452     time->parse(str, *cal, pos);
1453     if (pos.getIndex() != str.length()) {
1454         errln((UnicodeString)"FAIL: DateFormat::parse(17:45) failed at " +
1455               pos.getIndex());
1456         goto FAIL;
1457     }
1458 
1459     /* Check result */
1460     when = cal->getTime(ec);
1461     if (U_FAILURE(ec)) {
1462         errln((UnicodeString)"FAIL: cal->getTime() failed with " + u_errorName(ec));
1463         goto FAIL;
1464     }
1465     str.truncate(0);
1466     full->format(when, str);
1467     // Thursday, April 5, 2001 5:45:00 PM PDT 986517900000
1468     if (when == 986517900000.0) {
1469         logln("Ok: Parsed result: " + str);
1470     } else {
1471         errln("FAIL: Parsed result: " + str + ", exp 4/5/2001 5:45 PM");
1472     }
1473 
1474  FAIL:
1475     delete date;
1476     delete time;
1477     delete full;
1478     delete cal;
1479 }
1480 
1481 /**
1482  * Test DateFormat's parsing of space characters.  See jitterbug 1916.
1483  */
TestSpaceParsing()1484 void DateFormatTest::TestSpaceParsing() {
1485     const char* DATA[] = {
1486         "yyyy MM dd HH:mm:ss",
1487 
1488         // pattern, input, expected parse or NULL if expect parse failure
1489         "MMMM d yy", " 04 05 06",  "2006 04 05 00:00:00",
1490         NULL,        "04 05 06",   "2006 04 05 00:00:00",
1491 
1492         "MM d yy",   " 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,        "04 / 05 / 06", "2006 04 05 00:00:00",
1498         NULL,        "Apr / 05/ 06", "2006 04 05 00:00:00",
1499         NULL,        "Apr-05-06",    "2006 04 05 00:00:00",
1500         NULL,        "Apr 05, 2006", "2006 04 05 00:00:00",
1501 
1502         "MMMM d yy", " Apr 05 06", "2006 04 05 00:00:00",
1503         NULL,        "Apr 05 06",  "2006 04 05 00:00:00",
1504         NULL,        "Apr05 06",   "2006 04 05 00:00:00",
1505 
1506         "hh:mm:ss a", "12:34:56 PM", "1970 01 01 12:34:56",
1507         NULL,         "12:34:56PM",  "1970 01 01 12:34:56",
1508         NULL,         "12.34.56PM",  "1970 01 01 12:34:56",
1509         NULL,         "12 : 34 : 56  PM", "1970 01 01 12:34:56",
1510 
1511         "MM d yy 'at' hh:mm:ss a", "04/05/06 12:34:56 PM", "2006 04 05 12:34:56",
1512 
1513         "MMMM dd yyyy hh:mm a", "September 27, 1964 21:56 PM", "1964 09 28 09:56:00",
1514         NULL,                   "November 4, 2008 0:13 AM",    "2008 11 04 00:13:00",
1515 
1516         "HH'h'mm'min'ss's'", "12h34min56s", "1970 01 01 12:34:56",
1517         NULL,                "12h34mi56s",  "1970 01 01 12:34:56",
1518         NULL,                "12h34m56s",   "1970 01 01 12:34:56",
1519         NULL,                "12:34:56",    "1970 01 01 12:34:56"
1520     };
1521     const int32_t DATA_len = UPRV_LENGTHOF(DATA);
1522 
1523     expectParse(DATA, DATA_len, Locale("en"));
1524 }
1525 
1526 /**
1527  * Test handling of "HHmmss" pattern.
1528  */
TestExactCountFormat()1529 void DateFormatTest::TestExactCountFormat() {
1530     const char* DATA[] = {
1531         "yyyy MM dd HH:mm:ss",
1532 
1533         // pattern, input, expected parse or NULL if expect parse failure
1534         "HHmmss", "123456", "1970 01 01 12:34:56",
1535         NULL,     "12345",  "1970 01 01 01:23:45",
1536         NULL,     "1234",   NULL,
1537         NULL,     "00-05",  NULL,
1538         NULL,     "12-34",  NULL,
1539         NULL,     "00+05",  NULL,
1540         "ahhmm",  "PM730",  "1970 01 01 19:30:00",
1541     };
1542     const int32_t DATA_len = UPRV_LENGTHOF(DATA);
1543 
1544     expectParse(DATA, DATA_len, Locale("en"));
1545 }
1546 
1547 /**
1548  * Test handling of white space.
1549  */
TestWhiteSpaceParsing()1550 void DateFormatTest::TestWhiteSpaceParsing() {
1551     const char* DATA[] = {
1552         "yyyy MM dd",
1553 
1554         // pattern, input, expected parse or null if expect parse failure
1555 
1556         // Pattern space run should parse input text space run
1557         "MM   d yy",   " 04 01 03",    "2003 04 01",
1558         NULL,          " 04  01   03 ", "2003 04 01",
1559     };
1560     const int32_t DATA_len = UPRV_LENGTHOF(DATA);
1561 
1562     expectParse(DATA, DATA_len, Locale("en"));
1563 }
1564 
1565 
TestInvalidPattern()1566 void DateFormatTest::TestInvalidPattern() {
1567     UErrorCode ec = U_ZERO_ERROR;
1568     SimpleDateFormat f(UnicodeString("Yesterday"), ec);
1569     if (U_FAILURE(ec)) {
1570         dataerrln("Fail construct SimpleDateFormat: %s", u_errorName(ec));
1571         return;
1572     }
1573     UnicodeString out;
1574     FieldPosition pos;
1575     f.format((UDate)0, out, pos);
1576     logln(out);
1577     // The bug is that the call to format() will crash.  By not
1578     // crashing, the test passes.
1579 }
1580 
TestGreekMay()1581 void DateFormatTest::TestGreekMay() {
1582     UErrorCode ec = U_ZERO_ERROR;
1583     UDate date = -9896080848000.0;
1584     SimpleDateFormat fmt("EEEE, dd MMMM yyyy h:mm:ss a", Locale("el", "", ""), ec);
1585     if (U_FAILURE(ec)) {
1586         dataerrln("Fail construct SimpleDateFormat: %s", u_errorName(ec));
1587         return;
1588     }
1589     UnicodeString str;
1590     fmt.format(date, str);
1591     ParsePosition pos(0);
1592     UDate d2 = fmt.parse(str, pos);
1593     if (date != d2) {
1594         errln("FAIL: unable to parse strings where case-folding changes length");
1595     }
1596 }
1597 
TestStandAloneMonths()1598 void DateFormatTest::TestStandAloneMonths()
1599 {
1600     const char *EN_DATA[] = {
1601         "yyyy MM dd HH:mm:ss",
1602 
1603         "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",
1604         "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",
1605         "yyyy LLLL dd H:mm:ss", "F",  "2004 03 10 16:36:31", "2004 March 10 16:36:31",
1606         "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",
1607 
1608         "LLLL", "fp", "1970 01 01 0:00:00", "January",   "1970 01 01 0:00:00",
1609         "LLLL", "fp", "1970 02 01 0:00:00", "February",  "1970 02 01 0:00:00",
1610         "LLLL", "fp", "1970 03 01 0:00:00", "March",     "1970 03 01 0:00:00",
1611         "LLLL", "fp", "1970 04 01 0:00:00", "April",     "1970 04 01 0:00:00",
1612         "LLLL", "fp", "1970 05 01 0:00:00", "May",       "1970 05 01 0:00:00",
1613         "LLLL", "fp", "1970 06 01 0:00:00", "June",      "1970 06 01 0:00:00",
1614         "LLLL", "fp", "1970 07 01 0:00:00", "July",      "1970 07 01 0:00:00",
1615         "LLLL", "fp", "1970 08 01 0:00:00", "August",    "1970 08 01 0:00:00",
1616         "LLLL", "fp", "1970 09 01 0:00:00", "September", "1970 09 01 0:00:00",
1617         "LLLL", "fp", "1970 10 01 0:00:00", "October",   "1970 10 01 0:00:00",
1618         "LLLL", "fp", "1970 11 01 0:00:00", "November",  "1970 11 01 0:00:00",
1619         "LLLL", "fp", "1970 12 01 0:00:00", "December",  "1970 12 01 0:00:00",
1620 
1621         "LLL", "fp", "1970 01 01 0:00:00", "Jan", "1970 01 01 0:00:00",
1622         "LLL", "fp", "1970 02 01 0:00:00", "Feb", "1970 02 01 0:00:00",
1623         "LLL", "fp", "1970 03 01 0:00:00", "Mar", "1970 03 01 0:00:00",
1624         "LLL", "fp", "1970 04 01 0:00:00", "Apr", "1970 04 01 0:00:00",
1625         "LLL", "fp", "1970 05 01 0:00:00", "May", "1970 05 01 0:00:00",
1626         "LLL", "fp", "1970 06 01 0:00:00", "Jun", "1970 06 01 0:00:00",
1627         "LLL", "fp", "1970 07 01 0:00:00", "Jul", "1970 07 01 0:00:00",
1628         "LLL", "fp", "1970 08 01 0:00:00", "Aug", "1970 08 01 0:00:00",
1629         "LLL", "fp", "1970 09 01 0:00:00", "Sep", "1970 09 01 0:00:00",
1630         "LLL", "fp", "1970 10 01 0:00:00", "Oct", "1970 10 01 0:00:00",
1631         "LLL", "fp", "1970 11 01 0:00:00", "Nov", "1970 11 01 0:00:00",
1632         "LLL", "fp", "1970 12 01 0:00:00", "Dec", "1970 12 01 0:00:00",
1633     };
1634 
1635     const char *CS_DATA[] = {
1636         "yyyy MM dd HH:mm:ss",
1637 
1638         "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",
1639         "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",
1640         "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",
1641         "yyyy LLLL dd H:mm:ss", "F",  "2004 04 10 16:36:31", "2004 duben 10 16:36:31",
1642         "yyyy MMMM dd H:mm:ss", "F",  "2004 04 10 16:36:31", "2004 dubna 10 16:36:31",
1643         "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",
1644         "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",
1645 
1646         "LLLL", "fp", "1970 01 01 0:00:00", "leden",               "1970 01 01 0:00:00",
1647         "LLLL", "fp", "1970 02 01 0:00:00", "\\u00FAnor",           "1970 02 01 0:00:00",
1648         "LLLL", "fp", "1970 03 01 0:00:00", "b\\u0159ezen",         "1970 03 01 0:00:00",
1649         "LLLL", "fp", "1970 04 01 0:00:00", "duben",               "1970 04 01 0:00:00",
1650         "LLLL", "fp", "1970 05 01 0:00:00", "kv\\u011Bten",         "1970 05 01 0:00:00",
1651         "LLLL", "fp", "1970 06 01 0:00:00", "\\u010Derven",         "1970 06 01 0:00:00",
1652         "LLLL", "fp", "1970 07 01 0:00:00", "\\u010Dervenec",       "1970 07 01 0:00:00",
1653         "LLLL", "fp", "1970 08 01 0:00:00", "srpen",               "1970 08 01 0:00:00",
1654         "LLLL", "fp", "1970 09 01 0:00:00", "z\\u00E1\\u0159\\u00ED", "1970 09 01 0:00:00",
1655         "LLLL", "fp", "1970 10 01 0:00:00", "\\u0159\\u00EDjen",     "1970 10 01 0:00:00",
1656         "LLLL", "fp", "1970 11 01 0:00:00", "listopad",            "1970 11 01 0:00:00",
1657         "LLLL", "fp", "1970 12 01 0:00:00", "prosinec",            "1970 12 01 0:00:00",
1658 
1659         "LLL", "fp", "1970 01 01 0:00:00", "led",  "1970 01 01 0:00:00",
1660         "LLL", "fp", "1970 02 01 0:00:00", "\\u00FAno",  "1970 02 01 0:00:00",
1661         "LLL", "fp", "1970 03 01 0:00:00", "b\\u0159e",  "1970 03 01 0:00:00",
1662         "LLL", "fp", "1970 04 01 0:00:00", "dub",  "1970 04 01 0:00:00",
1663         "LLL", "fp", "1970 05 01 0:00:00", "kv\\u011B",  "1970 05 01 0:00:00",
1664         "LLL", "fp", "1970 06 01 0:00:00", "\\u010Dvn",  "1970 06 01 0:00:00",
1665         "LLL", "fp", "1970 07 01 0:00:00", "\\u010Dvc",  "1970 07 01 0:00:00",
1666         "LLL", "fp", "1970 08 01 0:00:00", "srp",  "1970 08 01 0:00:00",
1667         "LLL", "fp", "1970 09 01 0:00:00", "z\\u00E1\\u0159",  "1970 09 01 0:00:00",
1668         "LLL", "fp", "1970 10 01 0:00:00", "\\u0159\\u00EDj", "1970 10 01 0:00:00",
1669         "LLL", "fp", "1970 11 01 0:00:00", "lis", "1970 11 01 0:00:00",
1670         "LLL", "fp", "1970 12 01 0:00:00", "pro", "1970 12 01 0:00:00",
1671     };
1672 
1673     expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
1674     expect(CS_DATA, UPRV_LENGTHOF(CS_DATA), Locale("cs", "", ""));
1675 }
1676 
TestStandAloneDays()1677 void DateFormatTest::TestStandAloneDays()
1678 {
1679     const char *EN_DATA[] = {
1680         "yyyy MM dd HH:mm:ss",
1681 
1682         "cccc", "fp", "1970 01 04 0:00:00", "Sunday",    "1970 01 04 0:00:00",
1683         "cccc", "fp", "1970 01 05 0:00:00", "Monday",    "1970 01 05 0:00:00",
1684         "cccc", "fp", "1970 01 06 0:00:00", "Tuesday",   "1970 01 06 0:00:00",
1685         "cccc", "fp", "1970 01 07 0:00:00", "Wednesday", "1970 01 07 0:00:00",
1686         "cccc", "fp", "1970 01 01 0:00:00", "Thursday",  "1970 01 01 0:00:00",
1687         "cccc", "fp", "1970 01 02 0:00:00", "Friday",    "1970 01 02 0:00:00",
1688         "cccc", "fp", "1970 01 03 0:00:00", "Saturday",  "1970 01 03 0:00:00",
1689 
1690         "ccc", "fp", "1970 01 04 0:00:00", "Sun", "1970 01 04 0:00:00",
1691         "ccc", "fp", "1970 01 05 0:00:00", "Mon", "1970 01 05 0:00:00",
1692         "ccc", "fp", "1970 01 06 0:00:00", "Tue", "1970 01 06 0:00:00",
1693         "ccc", "fp", "1970 01 07 0:00:00", "Wed", "1970 01 07 0:00:00",
1694         "ccc", "fp", "1970 01 01 0:00:00", "Thu", "1970 01 01 0:00:00",
1695         "ccc", "fp", "1970 01 02 0:00:00", "Fri", "1970 01 02 0:00:00",
1696         "ccc", "fp", "1970 01 03 0:00:00", "Sat", "1970 01 03 0:00:00",
1697     };
1698 
1699     const char *CS_DATA[] = {
1700         "yyyy MM dd HH:mm:ss",
1701 
1702         "cccc", "fp", "1970 01 04 0:00:00", "ned\\u011Ble",       "1970 01 04 0:00:00",
1703         "cccc", "fp", "1970 01 05 0:00:00", "pond\\u011Bl\\u00ED", "1970 01 05 0:00:00",
1704         "cccc", "fp", "1970 01 06 0:00:00", "\\u00FAter\\u00FD",   "1970 01 06 0:00:00",
1705         "cccc", "fp", "1970 01 07 0:00:00", "st\\u0159eda",       "1970 01 07 0:00:00",
1706         "cccc", "fp", "1970 01 01 0:00:00", "\\u010Dtvrtek",      "1970 01 01 0:00:00",
1707         "cccc", "fp", "1970 01 02 0:00:00", "p\\u00E1tek",        "1970 01 02 0:00:00",
1708         "cccc", "fp", "1970 01 03 0:00:00", "sobota",            "1970 01 03 0:00:00",
1709 
1710         "ccc", "fp", "1970 01 04 0:00:00", "ne",      "1970 01 04 0:00:00",
1711         "ccc", "fp", "1970 01 05 0:00:00", "po",      "1970 01 05 0:00:00",
1712         "ccc", "fp", "1970 01 06 0:00:00", "\\u00FAt", "1970 01 06 0:00:00",
1713         "ccc", "fp", "1970 01 07 0:00:00", "st",      "1970 01 07 0:00:00",
1714         "ccc", "fp", "1970 01 01 0:00:00", "\\u010Dt", "1970 01 01 0:00:00",
1715         "ccc", "fp", "1970 01 02 0:00:00", "p\\u00E1", "1970 01 02 0:00:00",
1716         "ccc", "fp", "1970 01 03 0:00:00", "so",      "1970 01 03 0:00:00",
1717     };
1718 
1719     expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
1720     expect(CS_DATA, UPRV_LENGTHOF(CS_DATA), Locale("cs", "", ""));
1721 }
1722 
TestShortDays()1723 void DateFormatTest::TestShortDays()
1724 {
1725     const char *EN_DATA[] = {
1726         "yyyy MM dd HH:mm:ss",
1727 
1728         "EEEEEE, MMM d y", "fp", "2013 01 13 0:00:00", "Su, Jan 13 2013", "2013 01 13 0:00:00",
1729         "EEEEEE, MMM d y", "fp", "2013 01 16 0:00:00", "We, Jan 16 2013", "2013 01 16 0:00:00",
1730         "EEEEEE d",        "fp", "1970 01 17 0:00:00", "Sa 17",           "1970 01 17 0:00:00",
1731         "cccccc d",        "fp", "1970 01 17 0:00:00", "Sa 17",           "1970 01 17 0:00:00",
1732         "cccccc",          "fp", "1970 01 03 0:00:00", "Sa",              "1970 01 03 0:00:00",
1733     };
1734     const char *SV_DATA[] = {
1735         "yyyy MM dd HH:mm:ss",
1736 
1737         "EEEEEE d MMM y",  "fp", "2013 01 13 0:00:00", "s\\u00F6 13 jan. 2013", "2013 01 13 0:00:00",
1738         "EEEEEE d MMM y",  "fp", "2013 01 16 0:00:00", "on 16 jan. 2013",       "2013 01 16 0:00:00",
1739         "EEEEEE d",        "fp", "1970 01 17 0:00:00", "l\\u00F6 17",          "1970 01 17 0:00:00",
1740         "cccccc d",        "fp", "1970 01 17 0:00:00", "l\\u00F6 17",          "1970 01 17 0:00:00",
1741         "cccccc",          "fp", "1970 01 03 0:00:00", "l\\u00F6",             "1970 01 03 0:00:00",
1742     };
1743     expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
1744     expect(SV_DATA, UPRV_LENGTHOF(SV_DATA), Locale("sv", "", ""));
1745 }
1746 
TestNarrowNames()1747 void DateFormatTest::TestNarrowNames()
1748 {
1749     const char *EN_DATA[] = {
1750             "yyyy MM dd HH:mm:ss",
1751 
1752             "yyyy MMMMM dd H:mm:ss", "2004 03 10 16:36:31", "2004 M 10 16:36:31",
1753             "yyyy LLLLL dd H:mm:ss",  "2004 03 10 16:36:31", "2004 M 10 16:36:31",
1754 
1755             "MMMMM", "1970 01 01 0:00:00", "J",
1756             "MMMMM", "1970 02 01 0:00:00", "F",
1757             "MMMMM", "1970 03 01 0:00:00", "M",
1758             "MMMMM", "1970 04 01 0:00:00", "A",
1759             "MMMMM", "1970 05 01 0:00:00", "M",
1760             "MMMMM", "1970 06 01 0:00:00", "J",
1761             "MMMMM", "1970 07 01 0:00:00", "J",
1762             "MMMMM", "1970 08 01 0:00:00", "A",
1763             "MMMMM", "1970 09 01 0:00:00", "S",
1764             "MMMMM", "1970 10 01 0:00:00", "O",
1765             "MMMMM", "1970 11 01 0:00:00", "N",
1766             "MMMMM", "1970 12 01 0:00:00", "D",
1767 
1768             "LLLLL", "1970 01 01 0:00:00", "J",
1769             "LLLLL", "1970 02 01 0:00:00", "F",
1770             "LLLLL", "1970 03 01 0:00:00", "M",
1771             "LLLLL", "1970 04 01 0:00:00", "A",
1772             "LLLLL", "1970 05 01 0:00:00", "M",
1773             "LLLLL", "1970 06 01 0:00:00", "J",
1774             "LLLLL", "1970 07 01 0:00:00", "J",
1775             "LLLLL", "1970 08 01 0:00:00", "A",
1776             "LLLLL", "1970 09 01 0:00:00", "S",
1777             "LLLLL", "1970 10 01 0:00:00", "O",
1778             "LLLLL", "1970 11 01 0:00:00", "N",
1779             "LLLLL", "1970 12 01 0:00:00", "D",
1780 
1781             "EEEEE", "1970 01 04 0:00:00", "S",
1782             "EEEEE", "1970 01 05 0:00:00", "M",
1783             "EEEEE", "1970 01 06 0:00:00", "T",
1784             "EEEEE", "1970 01 07 0:00:00", "W",
1785             "EEEEE", "1970 01 01 0:00:00", "T",
1786             "EEEEE", "1970 01 02 0:00:00", "F",
1787             "EEEEE", "1970 01 03 0:00:00", "S",
1788 
1789             "ccccc", "1970 01 04 0:00:00", "S",
1790             "ccccc", "1970 01 05 0:00:00", "M",
1791             "ccccc", "1970 01 06 0:00:00", "T",
1792             "ccccc", "1970 01 07 0:00:00", "W",
1793             "ccccc", "1970 01 01 0:00:00", "T",
1794             "ccccc", "1970 01 02 0:00:00", "F",
1795             "ccccc", "1970 01 03 0:00:00", "S",
1796 
1797             "h:mm a",     "2015 01 01 10:00:00", "10:00 AM",
1798             "h:mm a",     "2015 01 01 22:00:00", "10:00 PM",
1799             "h:mm aaaaa", "2015 01 01 10:00:00", "10:00 a",
1800             "h:mm aaaaa", "2015 01 01 22:00:00", "10:00 p",
1801         };
1802 
1803         const char *CS_DATA[] = {
1804             "yyyy MM dd HH:mm:ss",
1805 
1806             "yyyy LLLLL dd H:mm:ss", "2004 04 10 16:36:31", "2004 4 10 16:36:31",
1807             "yyyy MMMMM dd H:mm:ss", "2004 04 10 16:36:31", "2004 4 10 16:36:31",
1808 
1809             "MMMMM", "1970 01 01 0:00:00", "1",
1810             "MMMMM", "1970 02 01 0:00:00", "2",
1811             "MMMMM", "1970 03 01 0:00:00", "3",
1812             "MMMMM", "1970 04 01 0:00:00", "4",
1813             "MMMMM", "1970 05 01 0:00:00", "5",
1814             "MMMMM", "1970 06 01 0:00:00", "6",
1815             "MMMMM", "1970 07 01 0:00:00", "7",
1816             "MMMMM", "1970 08 01 0:00:00", "8",
1817             "MMMMM", "1970 09 01 0:00:00", "9",
1818             "MMMMM", "1970 10 01 0:00:00", "10",
1819             "MMMMM", "1970 11 01 0:00:00", "11",
1820             "MMMMM", "1970 12 01 0:00:00", "12",
1821 
1822             "LLLLL", "1970 01 01 0:00:00", "1",
1823             "LLLLL", "1970 02 01 0:00:00", "2",
1824             "LLLLL", "1970 03 01 0:00:00", "3",
1825             "LLLLL", "1970 04 01 0:00:00", "4",
1826             "LLLLL", "1970 05 01 0:00:00", "5",
1827             "LLLLL", "1970 06 01 0:00:00", "6",
1828             "LLLLL", "1970 07 01 0:00:00", "7",
1829             "LLLLL", "1970 08 01 0:00:00", "8",
1830             "LLLLL", "1970 09 01 0:00:00", "9",
1831             "LLLLL", "1970 10 01 0:00:00", "10",
1832             "LLLLL", "1970 11 01 0:00:00", "11",
1833             "LLLLL", "1970 12 01 0:00:00", "12",
1834 
1835             "EEEEE", "1970 01 04 0:00:00", "N",
1836             "EEEEE", "1970 01 05 0:00:00", "P",
1837             "EEEEE", "1970 01 06 0:00:00", "\\u00DA",
1838             "EEEEE", "1970 01 07 0:00:00", "S",
1839             "EEEEE", "1970 01 01 0:00:00", "\\u010C",
1840             "EEEEE", "1970 01 02 0:00:00", "P",
1841             "EEEEE", "1970 01 03 0:00:00", "S",
1842 
1843             "ccccc", "1970 01 04 0:00:00", "N",
1844             "ccccc", "1970 01 05 0:00:00", "P",
1845             "ccccc", "1970 01 06 0:00:00", "\\u00DA",
1846             "ccccc", "1970 01 07 0:00:00", "S",
1847             "ccccc", "1970 01 01 0:00:00", "\\u010C",
1848             "ccccc", "1970 01 02 0:00:00", "P",
1849             "ccccc", "1970 01 03 0:00:00", "S",
1850 
1851             "h:mm a",     "2015 01 01 10:00:00", "10:00 dop.",
1852             "h:mm a",     "2015 01 01 22:00:00", "10:00 odp.",
1853             "h:mm aaaaa", "2015 01 01 10:00:00", "10:00 dop.",
1854             "h:mm aaaaa", "2015 01 01 22:00:00", "10:00 odp.",
1855         };
1856 
1857         const char *CA_DATA[] = {
1858             "yyyy MM dd HH:mm:ss",
1859 
1860             "h:mm a",     "2015 01 01 10:00:00", "10:00 a.\\u00A0m.",
1861             "h:mm a",     "2015 01 01 22:00:00", "10:00 p.\\u00A0m.",
1862             "h:mm aaaaa", "2015 01 01 10:00:00", "10:00 a.\\u00A0m.",
1863             "h:mm aaaaa", "2015 01 01 22:00:00", "10:00 p.\\u00A0m.",
1864         };
1865 
1866       expectFormat(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
1867       expectFormat(CS_DATA, UPRV_LENGTHOF(CS_DATA), Locale("cs", "", ""));
1868       expectFormat(CA_DATA, UPRV_LENGTHOF(CA_DATA), Locale("ca", "", ""));
1869 }
1870 
TestEras()1871 void DateFormatTest::TestEras()
1872 {
1873     const char *EN_DATA[] = {
1874         "yyyy MM dd",
1875 
1876         "MMMM dd yyyy G",    "fp", "1951 07 17", "July 17 1951 AD",          "1951 07 17",
1877         "MMMM dd yyyy GG",   "fp", "1951 07 17", "July 17 1951 AD",          "1951 07 17",
1878         "MMMM dd yyyy GGG",  "fp", "1951 07 17", "July 17 1951 AD",          "1951 07 17",
1879         "MMMM dd yyyy GGGG", "fp", "1951 07 17", "July 17 1951 Anno Domini", "1951 07 17",
1880 
1881         "MMMM dd yyyy G",    "fp", "-438 07 17", "July 17 0439 BC",            "-438 07 17",
1882         "MMMM dd yyyy GG",   "fp", "-438 07 17", "July 17 0439 BC",            "-438 07 17",
1883         "MMMM dd yyyy GGG",  "fp", "-438 07 17", "July 17 0439 BC",            "-438 07 17",
1884         "MMMM dd yyyy GGGG", "fp", "-438 07 17", "July 17 0439 Before Christ", "-438 07 17",
1885     };
1886 
1887     expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
1888 }
1889 
TestQuarters()1890 void DateFormatTest::TestQuarters()
1891 {
1892     const char *EN_DATA[] = {
1893         "yyyy MM dd",
1894 
1895         "Q",    "fp", "1970 01 01", "1",           "1970 01 01",
1896         "QQ",   "fp", "1970 04 01", "02",          "1970 04 01",
1897         "QQQ",  "fp", "1970 07 01", "Q3",          "1970 07 01",
1898         "QQQQ", "fp", "1970 10 01", "4th quarter", "1970 10 01",
1899 
1900         "q",    "fp", "1970 01 01", "1",           "1970 01 01",
1901         "qq",   "fp", "1970 04 01", "02",          "1970 04 01",
1902         "qqq",  "fp", "1970 07 01", "Q3",          "1970 07 01",
1903         "qqqq", "fp", "1970 10 01", "4th quarter", "1970 10 01",
1904 
1905         "Qyy",  "fp", "2015 04 01", "215",         "2015 04 01",
1906         "QQyy", "fp", "2015 07 01", "0315",        "2015 07 01",
1907     };
1908 
1909     expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
1910 }
1911 
1912 /**
1913  * Test parsing.  Input is an array that starts with the following
1914  * header:
1915  *
1916  * [0]   = pattern string to parse [i+2] with
1917  *
1918  * followed by test cases, each of which is 3 array elements:
1919  *
1920  * [i]   = pattern, or NULL to reuse prior pattern
1921  * [i+1] = input string
1922  * [i+2] = expected parse result (parsed with pattern [0])
1923  *
1924  * If expect parse failure, then [i+2] should be NULL.
1925  */
expectParse(const char ** data,int32_t data_length,const Locale & loc)1926 void DateFormatTest::expectParse(const char** data, int32_t data_length,
1927                                  const Locale& loc) {
1928     const UDate FAIL = (UDate) -1;
1929     const UnicodeString FAIL_STR("parse failure");
1930     int32_t i = 0;
1931 
1932     UErrorCode ec = U_ZERO_ERROR;
1933     SimpleDateFormat fmt("", loc, ec);
1934     SimpleDateFormat ref(data[i++], loc, ec);
1935     SimpleDateFormat gotfmt("G yyyy MM dd HH:mm:ss z", loc, ec);
1936     if (U_FAILURE(ec)) {
1937         dataerrln("FAIL: SimpleDateFormat constructor - %s", u_errorName(ec));
1938         return;
1939     }
1940 
1941     const char* currentPat = NULL;
1942     while (i<data_length) {
1943         const char* pattern  = data[i++];
1944         const char* input    = data[i++];
1945         const char* expected = data[i++];
1946 
1947         ec = U_ZERO_ERROR;
1948         if (pattern != NULL) {
1949             fmt.applyPattern(pattern);
1950             currentPat = pattern;
1951         }
1952         UDate got = fmt.parse(input, ec);
1953         UnicodeString gotstr(FAIL_STR);
1954         if (U_FAILURE(ec)) {
1955             got = FAIL;
1956         } else {
1957             gotstr.remove();
1958             gotfmt.format(got, gotstr);
1959         }
1960 
1961         UErrorCode ec2 = U_ZERO_ERROR;
1962         UDate exp = FAIL;
1963         UnicodeString expstr(FAIL_STR);
1964         if (expected != NULL) {
1965             expstr = expected;
1966             exp = ref.parse(expstr, ec2);
1967             if (U_FAILURE(ec2)) {
1968                 // This only happens if expected is in wrong format --
1969                 // should never happen once test is debugged.
1970                 errln("FAIL: Internal test error");
1971                 return;
1972             }
1973         }
1974 
1975         if (got == exp) {
1976             logln((UnicodeString)"Ok: " + input + " x " +
1977                   currentPat + " => " + gotstr);
1978         } else {
1979             errln((UnicodeString)"FAIL: " + input + " x " +
1980                   currentPat + " => " + gotstr + ", expected " +
1981                   expstr);
1982         }
1983     }
1984 }
1985 
1986 /**
1987  * Test formatting and parsing.  Input is an array that starts
1988  * with the following header:
1989  *
1990  * [0]   = pattern string to parse [i+2] with
1991  *
1992  * followed by test cases, each of which is 3 array elements:
1993  *
1994  * [i]   = pattern, or null to reuse prior pattern
1995  * [i+1] = control string, either "fp", "pf", or "F".
1996  * [i+2..] = data strings
1997  *
1998  * The number of data strings depends on the control string.
1999  * Examples:
2000  * 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",
2001  * 'f': Format date [i+2] (as parsed using pattern [0]) and expect string [i+3].
2002  * 'p': Parse string [i+3] and expect date [i+4].
2003  *
2004  * 2. "y/M/d H:mm:ss.SSS", "F", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.567"
2005  * 'F': Format date [i+2] and expect string [i+3],
2006  *      then parse string [i+3] and expect date [i+2].
2007  *
2008  * 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",
2009  * 'p': Parse string [i+2] and expect date [i+3].
2010  * 'f': Format date [i+3] and expect string [i+4].
2011  */
expect(const char ** data,int32_t data_length,const Locale & loc)2012 void DateFormatTest::expect(const char** data, int32_t data_length,
2013                             const Locale& loc) {
2014     int32_t i = 0;
2015     UErrorCode ec = U_ZERO_ERROR;
2016     UnicodeString str, str2;
2017     SimpleDateFormat fmt("", loc, ec);
2018     SimpleDateFormat ref(data[i++], loc, ec);
2019     SimpleDateFormat univ("EE G yyyy MM dd HH:mm:ss.SSS z", loc, ec);
2020     if (U_FAILURE(ec)) {
2021         dataerrln("Fail construct SimpleDateFormat: %s", u_errorName(ec));
2022         return;
2023     }
2024 
2025     UnicodeString currentPat;
2026     while (i<data_length) {
2027         const char* pattern  = data[i++];
2028         if (pattern != NULL) {
2029             fmt.applyPattern(pattern);
2030             currentPat = pattern;
2031         }
2032 
2033         const char* control = data[i++];
2034 
2035         if (uprv_strcmp(control, "fp") == 0) {
2036             // 'f'
2037             const char* datestr = data[i++];
2038             const char* string = data[i++];
2039             UDate date = ref.parse(ctou(datestr), ec);
2040             if (!assertSuccess("parse", ec)) return;
2041             assertEquals((UnicodeString)"\"" + currentPat + "\".format(" + datestr + ")",
2042                          ctou(string),
2043                          fmt.format(date, str.remove()));
2044             // 'p'
2045             datestr = data[i++];
2046             date = ref.parse(ctou(datestr), ec);
2047             if (!assertSuccess("parse", ec)) return;
2048             UDate parsedate = fmt.parse(ctou(string), ec);
2049             if (assertSuccess((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")", ec)) {
2050                 assertEquals((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")",
2051                              univ.format(date, str.remove()),
2052                              univ.format(parsedate, str2.remove()));
2053             }
2054         }
2055 
2056         else if (uprv_strcmp(control, "pf") == 0) {
2057             // 'p'
2058             const char* string = data[i++];
2059             const char* datestr = data[i++];
2060             UDate date = ref.parse(ctou(datestr), ec);
2061             if (!assertSuccess("parse", ec)) return;
2062             UDate parsedate = fmt.parse(ctou(string), ec);
2063             if (assertSuccess((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")", ec)) {
2064                 assertEquals((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")",
2065                              univ.format(date, str.remove()),
2066                              univ.format(parsedate, str2.remove()));
2067             }
2068             // 'f'
2069             string = data[i++];
2070             assertEquals((UnicodeString)"\"" + currentPat + "\".format(" + datestr + ")",
2071                          ctou(string),
2072                          fmt.format(date, str.remove()));
2073         }
2074 
2075         else if (uprv_strcmp(control, "F") == 0) {
2076             const char* datestr  = data[i++];
2077             const char* string   = data[i++];
2078             UDate date = ref.parse(ctou(datestr), ec);
2079             if (!assertSuccess("parse", ec)) return;
2080             assertEquals((UnicodeString)"\"" + currentPat + "\".format(" + datestr + ")",
2081                          ctou(string),
2082                          fmt.format(date, str.remove()));
2083 
2084             UDate parsedate = fmt.parse(string, ec);
2085             if (assertSuccess((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")", ec)) {
2086                 assertEquals((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")",
2087                              univ.format(date, str.remove()),
2088                              univ.format(parsedate, str2.remove()));
2089             }
2090         }
2091 
2092         else {
2093             errln((UnicodeString)"FAIL: Invalid control string " + control);
2094             return;
2095         }
2096     }
2097 }
2098 
2099 /**
2100  * Test formatting.  Input is an array that starts
2101  * with the following header:
2102  *
2103  * [0]   = pattern string to parse [i+2] with
2104  *
2105  * followed by test cases, each of which is 3 array elements:
2106  *
2107  * [i]   = pattern, or null to reuse prior pattern
2108  * [i+1] = data string a
2109  * [i+2] = data string b
2110  *
2111  * Examples:
2112  * Format date [i+1] and expect string [i+2].
2113  *
2114  * "y/M/d H:mm:ss.SSSS", "2004/3/10 16:36:31.5679", "2004 03 10 16:36:31.567"
2115  */
expectFormat(const char ** data,int32_t data_length,const Locale & loc)2116 void DateFormatTest::expectFormat(const char** data, int32_t data_length,
2117                             const Locale& loc) {
2118     int32_t i = 0;
2119     UErrorCode ec = U_ZERO_ERROR;
2120     UnicodeString str, str2;
2121     SimpleDateFormat fmt("", loc, ec);
2122     SimpleDateFormat ref(data[i++], loc, ec);
2123     SimpleDateFormat univ("EE G yyyy MM dd HH:mm:ss.SSS z", loc, ec);
2124     if (U_FAILURE(ec)) {
2125         dataerrln("Fail construct SimpleDateFormat: %s", u_errorName(ec));
2126         return;
2127     }
2128 
2129     UnicodeString currentPat;
2130 
2131     while (i<data_length) {
2132         const char* pattern  = data[i++];
2133         if (pattern != NULL) {
2134             fmt.applyPattern(pattern);
2135             currentPat = pattern;
2136         }
2137 
2138         const char* datestr = data[i++];
2139         const char* string = data[i++];
2140         UDate date = ref.parse(ctou(datestr), ec);
2141         if (!assertSuccess("parse", ec)) return;
2142         assertEquals((UnicodeString)"\"" + currentPat + "\".format(" + datestr + ")",
2143                         ctou(string),
2144                         fmt.format(date, str.remove()));
2145     }
2146 }
2147 
TestGenericTime()2148 void DateFormatTest::TestGenericTime() {
2149   const Locale en("en");
2150   // Note: We no longer parse strings in different styles.
2151 /*
2152   const char* ZDATA[] = {
2153         "yyyy MM dd HH:mm zzz",
2154         // round trip
2155         "y/M/d H:mm zzzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Standard Time",
2156         "y/M/d H:mm zzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
2157         "y/M/d H:mm vvvv", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
2158         "y/M/d H:mm v", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PT",
2159         // non-generic timezone string influences dst offset even if wrong for date/time
2160         "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",
2161         "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",
2162         "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",
2163         "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",
2164         // generic timezone generates dst offset appropriate for local time
2165         "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",
2166         "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",
2167         "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",
2168         "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",
2169         // daylight savings time transition edge cases.
2170         // time to parse does not really exist, PT interpreted as earlier time
2171         "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",
2172         "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",
2173         "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",
2174         "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",
2175         "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",
2176         "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",
2177         "y/M/d H:mm", "pf", "2005/4/3 2:30", "2005 04 03 03:30 PDT", "2005/4/3 3:30",
2178         // time to parse is ambiguous, PT interpreted as later time
2179         "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",
2180         "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",
2181         "y/M/d H:mm", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30",
2182 
2183         "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",
2184         "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",
2185         "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",
2186         "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",
2187         "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",
2188         "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",
2189         "y/M/d H:mm", "pf", "2004/10/31 1:30", "2004 10 31 01:30 PST", "2004/10/31 1:30",
2190   };
2191 */
2192   const char* ZDATA[] = {
2193         "yyyy MM dd HH:mm zzz",
2194         // round trip
2195         "y/M/d H:mm zzzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Standard Time",
2196         "y/M/d H:mm zzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
2197         "y/M/d H:mm vvvv", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
2198         "y/M/d H:mm v", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PT",
2199         // non-generic timezone string influences dst offset even if wrong for date/time
2200         "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",
2201         "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",
2202         // generic timezone generates dst offset appropriate for local time
2203         "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",
2204         "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",
2205         "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",
2206         "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",
2207         // daylight savings time transition edge cases.
2208         // time to parse does not really exist, PT interpreted as earlier time
2209         "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",
2210         "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",
2211         "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",
2212         "y/M/d H:mm", "pf", "2005/4/3 2:30", "2005 04 03 03:30 PDT", "2005/4/3 3:30",
2213         // time to parse is ambiguous, PT interpreted as later time
2214         "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",
2215         "y/M/d H:mm", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30",
2216 
2217         "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",
2218         "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",
2219         "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",
2220         "y/M/d H:mm", "pf", "2004/10/31 1:30", "2004 10 31 01:30 PST", "2004/10/31 1:30",
2221   };
2222 
2223   const int32_t ZDATA_length = UPRV_LENGTHOF(ZDATA);
2224   expect(ZDATA, ZDATA_length, en);
2225 
2226   UErrorCode status = U_ZERO_ERROR;
2227 
2228   logln("cross format/parse tests");    // Note: We no longer support cross format/parse
2229   UnicodeString basepat("yy/MM/dd H:mm ");
2230   SimpleDateFormat formats[] = {
2231     SimpleDateFormat(basepat + "vvv", en, status),
2232     SimpleDateFormat(basepat + "vvvv", en, status),
2233     SimpleDateFormat(basepat + "zzz", en, status),
2234     SimpleDateFormat(basepat + "zzzz", en, status)
2235   };
2236   if (U_FAILURE(status)) {
2237     dataerrln("Fail construct SimpleDateFormat: %s", u_errorName(status));
2238     return;
2239   }
2240   const int32_t formats_length = UPRV_LENGTHOF(formats);
2241 
2242   UnicodeString test;
2243   SimpleDateFormat univ("yyyy MM dd HH:mm zzz", en, status);
2244   ASSERT_OK(status);
2245   const UnicodeString times[] = {
2246     "2004 01 02 03:04 PST",
2247     "2004 07 08 09:10 PDT"
2248   };
2249   int32_t times_length = UPRV_LENGTHOF(times);
2250   for (int i = 0; i < times_length; ++i) {
2251     UDate d = univ.parse(times[i], status);
2252     logln(UnicodeString("\ntime: ") + d);
2253     for (int j = 0; j < formats_length; ++j) {
2254       test.remove();
2255       formats[j].format(d, test);
2256       logln("\ntest: '" + test + "'");
2257       for (int k = 0; k < formats_length; ++k) {
2258         UDate t = formats[k].parse(test, status);
2259         if (U_SUCCESS(status)) {
2260           if (d != t) {
2261             errln((UnicodeString)"FAIL: format " + k +
2262                   " incorrectly parsed output of format " + j +
2263                   " (" + test + "), returned " +
2264                   dateToString(t) + " instead of " + dateToString(d));
2265           } else {
2266             logln((UnicodeString)"OK: format " + k + " parsed ok");
2267           }
2268         } else if (status == U_PARSE_ERROR) {
2269           errln((UnicodeString)"FAIL: format " + k +
2270                 " could not parse output of format " + j +
2271                 " (" + test + ")");
2272         }
2273       }
2274     }
2275   }
2276 }
2277 
TestGenericTimeZoneOrder()2278 void DateFormatTest::TestGenericTimeZoneOrder() {
2279   // generic times should parse the same no matter what the placement of the time zone string
2280 
2281   // Note: We no longer support cross style format/parse
2282 
2283   //const char* XDATA[] = {
2284   //  "yyyy MM dd HH:mm zzz",
2285   //  // standard time, explicit daylight/standard
2286   //  "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",
2287   //  "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",
2288   //  "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",
2289 
2290   //  // standard time, generic
2291   //  "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",
2292   //  "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",
2293   //  "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",
2294 
2295   //  // dahylight time, explicit daylight/standard
2296   //  "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",
2297   //  "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",
2298   //  "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",
2299 
2300   //  // daylight time, generic
2301   //  "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",
2302   //  "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",
2303   //  "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",
2304   //};
2305   const char* XDATA[] = {
2306     "yyyy MM dd HH:mm zzz",
2307     // standard time, explicit daylight/standard
2308     "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",
2309     "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",
2310     "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",
2311 
2312     // standard time, generic
2313     "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",
2314     "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",
2315     "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",
2316 
2317     // dahylight time, explicit daylight/standard
2318     "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",
2319     "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",
2320     "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",
2321 
2322     // daylight time, generic
2323     "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",
2324     "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",
2325     "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",
2326   };
2327   const int32_t XDATA_length = UPRV_LENGTHOF(XDATA);
2328   Locale en("en");
2329   expect(XDATA, XDATA_length, en);
2330 }
2331 
TestZTimeZoneParsing(void)2332 void DateFormatTest::TestZTimeZoneParsing(void) {
2333     UErrorCode status = U_ZERO_ERROR;
2334     const Locale en("en");
2335     UnicodeString test;
2336     //SimpleDateFormat univ("yyyy-MM-dd'T'HH:mm Z", en, status);
2337     SimpleDateFormat univ("HH:mm Z", en, status);
2338     if (failure(status, "construct SimpleDateFormat", TRUE)) return;
2339     const TimeZone *t = TimeZone::getGMT();
2340     univ.setTimeZone(*t);
2341 
2342     univ.setLenient(false);
2343     ParsePosition pp(0);
2344     struct {
2345         UnicodeString input;
2346         UnicodeString expected_result;
2347     } tests[] = {
2348         { "11:00 -0200", "13:00 +0000" },
2349         { "11:00 +0200", "09:00 +0000" },
2350         { "11:00 +0400", "07:00 +0000" },
2351         { "11:00 +0530", "05:30 +0000" }
2352     };
2353 
2354     UnicodeString result;
2355     int32_t tests_length = UPRV_LENGTHOF(tests);
2356     for (int i = 0; i < tests_length; ++i) {
2357         pp.setIndex(0);
2358         UDate d = univ.parse(tests[i].input, pp);
2359         if(pp.getIndex() != tests[i].input.length()){
2360             errln("Test %i: setZoneString() did not succeed. Consumed: %i instead of %i",
2361                   i, pp.getIndex(), tests[i].input.length());
2362             return;
2363         }
2364         result.remove();
2365         univ.format(d, result);
2366         if(result != tests[i].expected_result) {
2367             errln("Expected " + tests[i].expected_result
2368                   + " got " + result);
2369             return;
2370         }
2371         logln("SUCCESS: Parsed " + tests[i].input
2372               + " got " + result
2373               + " expected " + tests[i].expected_result);
2374     }
2375 }
2376 
TestHost(void)2377 void DateFormatTest::TestHost(void)
2378 {
2379 #if U_PLATFORM_USES_ONLY_WIN32_API
2380     Win32DateTimeTest::testLocales(this);
2381 #endif
2382 }
2383 
2384 // Relative Date Tests
2385 
TestRelative(int daysdelta,const Locale & loc,const char * expectChars)2386 void DateFormatTest::TestRelative(int daysdelta,
2387                                   const Locale& loc,
2388                                   const char *expectChars) {
2389     char banner[25];
2390     sprintf(banner, "%d", daysdelta);
2391     UnicodeString bannerStr(banner, "");
2392 
2393     UErrorCode status = U_ZERO_ERROR;
2394 
2395     FieldPosition pos(FieldPosition::DONT_CARE);
2396     UnicodeString test;
2397     Locale en("en");
2398     DateFormat *fullrelative = DateFormat::createDateInstance(DateFormat::kFullRelative, loc);
2399 
2400     if (fullrelative == NULL) {
2401         dataerrln("DateFormat::createDateInstance(DateFormat::kFullRelative, %s) returned NULL", loc.getName());
2402         return;
2403     }
2404 
2405     DateFormat *full         = DateFormat::createDateInstance(DateFormat::kFull        , loc);
2406 
2407     if (full == NULL) {
2408         errln("DateFormat::createDateInstance(DateFormat::kFull, %s) returned NULL", loc.getName());
2409         return;
2410     }
2411 
2412     DateFormat *en_full =         DateFormat::createDateInstance(DateFormat::kFull,         en);
2413 
2414     if (en_full == NULL) {
2415         errln("DateFormat::createDateInstance(DateFormat::kFull, en) returned NULL");
2416         return;
2417     }
2418 
2419     DateFormat *en_fulltime =         DateFormat::createDateTimeInstance(DateFormat::kFull,DateFormat::kFull,en);
2420 
2421     if (en_fulltime == NULL) {
2422         errln("DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, en) returned NULL");
2423         return;
2424     }
2425 
2426     UnicodeString result;
2427     UnicodeString normalResult;
2428     UnicodeString expect;
2429     UnicodeString parseResult;
2430 
2431     Calendar *c = Calendar::createInstance(status);
2432 
2433     // Today = Today
2434     c->setTime(Calendar::getNow(), status);
2435     if(daysdelta != 0) {
2436         c->add(Calendar::DATE,daysdelta,status);
2437     }
2438     ASSERT_OK(status);
2439 
2440     // calculate the expected string
2441     if(expectChars != NULL) {
2442         expect = expectChars;
2443     } else {
2444         full->format(*c, expect, pos); // expected = normal full
2445     }
2446 
2447     fullrelative   ->format(*c, result, pos);
2448     en_full        ->format(*c, normalResult, pos);
2449 
2450     if(result != expect) {
2451         errln("FAIL: Relative Format ["+bannerStr+"] of "+normalResult+" failed, expected "+expect+" but got " + result);
2452     } else {
2453         logln("PASS: Relative Format ["+bannerStr+"] of "+normalResult+" got " + result);
2454     }
2455 
2456 
2457     //verify
2458     UDate d = fullrelative->parse(result, status);
2459     ASSERT_OK(status);
2460 
2461     UnicodeString parseFormat; // parse rel->format full
2462     en_full->format(d, parseFormat, status);
2463 
2464     UnicodeString origFormat;
2465     en_full->format(*c, origFormat, pos);
2466 
2467     if(parseFormat!=origFormat) {
2468         errln("FAIL: Relative Parse ["+bannerStr+"] of "+result+" failed, expected "+parseFormat+" but got "+origFormat);
2469     } else {
2470         logln("PASS: Relative Parse ["+bannerStr+"] of "+result+" passed, got "+parseFormat);
2471     }
2472 
2473     delete full;
2474     delete fullrelative;
2475     delete en_fulltime;
2476     delete en_full;
2477     delete c;
2478 }
2479 
2480 
TestRelative(void)2481 void DateFormatTest::TestRelative(void)
2482 {
2483     Locale en("en");
2484     TestRelative( 0, en, "today");
2485     TestRelative(-1, en, "yesterday");
2486     TestRelative( 1, en, "tomorrow");
2487     TestRelative( 2, en, NULL);
2488     TestRelative( -2, en, NULL);
2489     TestRelative( 3, en, NULL);
2490     TestRelative( -3, en, NULL);
2491     TestRelative( 300, en, NULL);
2492     TestRelative( -300, en, NULL);
2493 }
2494 
TestRelativeClone(void)2495 void DateFormatTest::TestRelativeClone(void)
2496 {
2497     /*
2498     Verify that a cloned formatter gives the same results
2499     and is useable after the original has been deleted.
2500     */
2501     UErrorCode status = U_ZERO_ERROR;
2502     Locale loc("en");
2503     UDate now = Calendar::getNow();
2504     DateFormat *full = DateFormat::createDateInstance(DateFormat::kFullRelative, loc);
2505     if (full == NULL) {
2506         dataerrln("FAIL: Can't create Relative date instance");
2507         return;
2508     }
2509     UnicodeString result1;
2510     full->format(now, result1, status);
2511     Format *fullClone = full->clone();
2512     delete full;
2513     full = NULL;
2514 
2515     UnicodeString result2;
2516     fullClone->format(now, result2, status);
2517     ASSERT_OK(status);
2518     if (result1 != result2) {
2519         errln("FAIL: Clone returned different result from non-clone.");
2520     }
2521     delete fullClone;
2522 }
2523 
TestHostClone(void)2524 void DateFormatTest::TestHostClone(void)
2525 {
2526     /*
2527     Verify that a cloned formatter gives the same results
2528     and is useable after the original has been deleted.
2529     */
2530     // This is mainly important on Windows.
2531     UErrorCode status = U_ZERO_ERROR;
2532     Locale loc("en_US@compat=host");
2533     UDate now = Calendar::getNow();
2534     DateFormat *full = DateFormat::createDateInstance(DateFormat::kFull, loc);
2535     if (full == NULL) {
2536         dataerrln("FAIL: Can't create host date instance");
2537         return;
2538     }
2539     UnicodeString result1;
2540     full->format(now, result1, status);
2541     Format *fullClone = full->clone();
2542     delete full;
2543     full = NULL;
2544 
2545     UnicodeString result2;
2546     fullClone->format(now, result2, status);
2547     ASSERT_OK(status);
2548     if (result1 != result2) {
2549         errln("FAIL: Clone returned different result from non-clone.");
2550     }
2551     delete fullClone;
2552 }
2553 
TestHebrewClone(void)2554 void DateFormatTest::TestHebrewClone(void)
2555 {
2556     /*
2557     Verify that a cloned formatter gives the same results
2558     and is useable after the original has been deleted.
2559     */
2560     UErrorCode status = U_ZERO_ERROR;
2561     Locale loc("he@calendar=hebrew");
2562     UDate now = Calendar::getNow();
2563     LocalPointer<DateFormat> fmt(
2564             DateFormat::createDateInstance(DateFormat::kLong, loc));
2565     if (fmt.isNull()) {
2566         dataerrln("FAIL: Can't create Hebrew date instance");
2567         return;
2568     }
2569     UnicodeString result1;
2570     fmt->format(now, result1, status);
2571     LocalPointer<Format> fmtClone(fmt->clone());
2572 
2573     // free fmt to be sure that fmtClone is independent of fmt.
2574     fmt.adoptInstead(NULL);
2575 
2576     UnicodeString result2;
2577     fmtClone->format(now, result2, status);
2578     ASSERT_OK(status);
2579     if (result1 != result2) {
2580         errln("FAIL: Clone returned different result from non-clone.");
2581     }
2582 }
2583 
getActualAndValidLocales(const Format & fmt,Locale & valid,Locale & actual)2584 static UBool getActualAndValidLocales(
2585         const Format &fmt, Locale &valid, Locale &actual) {
2586     const SimpleDateFormat* dat = dynamic_cast<const SimpleDateFormat*>(&fmt);
2587     if (dat == NULL) {
2588         return FALSE;
2589     }
2590     const DateFormatSymbols *sym = dat->getDateFormatSymbols();
2591     if (sym == NULL) {
2592         return FALSE;
2593     }
2594     UErrorCode status = U_ZERO_ERROR;
2595     valid = sym->getLocale(ULOC_VALID_LOCALE, status);
2596     actual = sym->getLocale(ULOC_ACTUAL_LOCALE, status);
2597     return U_SUCCESS(status);
2598 }
2599 
TestDateFormatSymbolsClone(void)2600 void DateFormatTest::TestDateFormatSymbolsClone(void)
2601 {
2602     /*
2603     Verify that a cloned formatter gives the same results
2604     and is useable after the original has been deleted.
2605     */
2606     Locale loc("de_CH_LUCERNE");
2607     LocalPointer<DateFormat> fmt(
2608             DateFormat::createDateInstance(DateFormat::kDefault, loc));
2609     if (fmt.isNull()) {
2610         dataerrln("FAIL: DateFormat::createDateInstance failed for %s", loc.getName());
2611         return;
2612     }
2613     Locale valid1;
2614     Locale actual1;
2615     if (!getActualAndValidLocales(*fmt, valid1, actual1)) {
2616         dataerrln("FAIL: Could not fetch valid + actual locales");
2617         return;
2618     }
2619     LocalPointer<Format> fmtClone(fmt->clone());
2620 
2621     // Free fmt to be sure that fmtClone is really independent of fmt.
2622     fmt.adoptInstead(NULL);
2623     Locale valid2;
2624     Locale actual2;
2625     if (!getActualAndValidLocales(*fmtClone, valid2, actual2)) {
2626         errln("FAIL: Could not fetch valid + actual locales");
2627         return;
2628     }
2629     if (valid1 != valid2 || actual1 != actual2) {
2630         errln("Date format symbol locales of clone don't match original");
2631     }
2632 }
2633 
TestTimeZoneDisplayName()2634 void DateFormatTest::TestTimeZoneDisplayName()
2635 {
2636     // This test data was ported from ICU4J.  Don't know why the 6th column in there because it's not being
2637     // used currently.
2638     const char *fallbackTests[][6]  = {
2639         { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
2640         { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
2641         { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZZ", "-08:00", "-8:00" },
2642         { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "PST", "America/Los_Angeles" },
2643         { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "Pacific Standard Time", "America/Los_Angeles" },
2644         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
2645         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
2646         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "PDT", "America/Los_Angeles" },
2647         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "Pacific Daylight Time", "America/Los_Angeles" },
2648         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "PT", "America/Los_Angeles" },
2649         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "Pacific Time", "America/Los_Angeles" },
2650         { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "VVVV", "Los Angeles Time", "America/Los_Angeles" },
2651         { "en_GB", "America/Los_Angeles", "2004-01-15T12:00:00Z", "z", "GMT-8", "America/Los_Angeles" },
2652         { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "Z", "-0700", "-7:00" },
2653         { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
2654         { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "z", "MST", "America/Phoenix" },
2655         { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "zzzz", "Mountain Standard Time", "America/Phoenix" },
2656         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
2657         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
2658         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "z", "MST", "America/Phoenix" },
2659         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "zzzz", "Mountain Standard Time", "America/Phoenix" },
2660         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "v", "MST", "America/Phoenix" },
2661         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "vvvv", "Mountain Standard Time", "America/Phoenix" },
2662         { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "VVVV", "Phoenix Time", "America/Phoenix" },
2663 
2664         { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2665         { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2666         { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2667         { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
2668         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2669         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2670         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2671         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
2672         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires Time", "America/Buenos_Aires" },
2673         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentina Standard Time", "America/Buenos_Aires" },
2674         { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "VVVV", "Buenos Aires Time", "America/Buenos_Aires" },
2675 
2676         { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2677         { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2678         { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2679         { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
2680         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2681         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2682         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2683         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
2684         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires Time", "America/Buenos_Aires" },
2685         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentina Standard Time", "America/Buenos_Aires" },
2686         { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "VVVV", "Buenos Aires Time", "America/Buenos_Aires" },
2687 
2688         { "en", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
2689         { "en", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
2690         { "en", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
2691         { "en", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "Cuba Standard Time", "-5:00" },
2692         { "en", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
2693         { "en", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
2694         { "en", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
2695         { "en", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "Cuba Daylight Time", "-4:00" },
2696         { "en", "America/Havana", "2004-07-15T00:00:00Z", "v", "Cuba Time", "America/Havana" },
2697         { "en", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "Cuba Time", "America/Havana" },
2698         { "en", "America/Havana", "2004-07-15T00:00:00Z", "VVVV", "Cuba Time", "America/Havana" },
2699 
2700         { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
2701         { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
2702         { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
2703         { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "Australian Eastern Daylight Time", "+11:00" },
2704         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
2705         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
2706         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
2707         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "Australian Eastern Standard Time", "+10:00" },
2708         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "Sydney Time", "Australia/Sydney" },
2709         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "Eastern Australia Time", "Australia/Sydney" },
2710         { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "VVVV", "Sydney Time", "Australia/Sydney" },
2711 
2712         { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
2713         { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
2714         { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
2715         { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "Australian Eastern Daylight Time", "+11:00" },
2716         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
2717         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
2718         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
2719         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "Australian Eastern Standard Time", "+10:00" },
2720         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "Sydney Time", "Australia/Sydney" },
2721         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "Eastern Australia Time", "Australia/Sydney" },
2722         { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "VVVV", "Sydney Time", "Australia/Sydney" },
2723 
2724         { "en", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
2725         { "en", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
2726         { "en", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
2727         { "en", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "Greenwich Mean Time", "+0:00" },
2728         { "en", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
2729         { "en", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
2730         { "en", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "Europe/London" },
2731         { "en", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "British Summer Time", "Europe/London" },
2732     // icu en.txt has exemplar city for this time zone
2733         { "en", "Europe/London", "2004-07-15T00:00:00Z", "v", "United Kingdom Time", "Europe/London" },
2734         { "en", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "United Kingdom Time", "Europe/London" },
2735         { "en", "Europe/London", "2004-07-15T00:00:00Z", "VVVV", "United Kingdom Time", "Europe/London" },
2736 
2737         { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2738         { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2739         { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2740         { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
2741         { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2742         { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2743         { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2744         { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
2745         { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
2746         { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
2747 
2748         // JB#5150
2749         { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
2750         { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
2751         { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
2752         { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "India Standard Time", "+5:30" },
2753         { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
2754         { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
2755         { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
2756         { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "India Standard Time", "+5:30" },
2757         { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "India Time", "Asia/Calcutta" },
2758         { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "India Standard Time", "Asia/Calcutta" },
2759 
2760         // Proper CLDR primary zone support #9733
2761         { "en", "America/Santiago", "2013-01-01T00:00:00Z", "VVVV", "Chile Time", "America/Santiago" },
2762         { "en", "Pacific/Easter", "2013-01-01T00:00:00Z", "VVVV", "Easter Time", "Pacific/Easter" },
2763 
2764         // ==========
2765 
2766         { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
2767         { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
2768         { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "-8:00" },
2769         { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "Nordamerikanische Westk\\u00fcsten-Normalzeit", "-8:00" },
2770         { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
2771         { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
2772         { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "-7:00" },
2773         { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "Nordamerikanische Westk\\u00fcsten-Sommerzeit", "-7:00" },
2774         { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "Los Angeles Zeit", "America/Los_Angeles" },
2775         { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "Nordamerikanische Westk\\u00fcstenzeit", "America/Los_Angeles" },
2776 
2777         { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2778         { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2779         { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2780         { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
2781         { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2782         { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2783         { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2784         { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
2785         { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires Zeit", "America/Buenos_Aires" },
2786         { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentinische Normalzeit", "America/Buenos_Aires" },
2787 
2788         { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2789         { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2790         { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2791         { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
2792         { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2793         { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2794         { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2795         { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
2796         { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires Zeit", "America/Buenos_Aires" },
2797         { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentinische Normalzeit", "America/Buenos_Aires" },
2798 
2799         { "de", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
2800         { "de", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
2801         { "de", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
2802         { "de", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "Kubanische Normalzeit", "-5:00" },
2803         { "de", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
2804         { "de", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
2805         { "de", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
2806         { "de", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "Kubanische Sommerzeit", "-4:00" },
2807         { "de", "America/Havana", "2004-07-15T00:00:00Z", "v", "Kuba Zeit", "America/Havana" },
2808         { "de", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "Kubanische Zeit", "America/Havana" },
2809         // added to test proper fallback of country name
2810         { "de_CH", "America/Havana", "2004-07-15T00:00:00Z", "v", "Kuba Zeit", "America/Havana" },
2811         { "de_CH", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "Kubanische Zeit", "America/Havana" },
2812 
2813         { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
2814         { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
2815         { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
2816         { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "Ostaustralische Sommerzeit", "+11:00" },
2817         { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
2818         { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
2819         { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
2820         { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "Ostaustralische Normalzeit", "+10:00" },
2821         { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "Sydney Zeit", "Australia/Sydney" },
2822         { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "Ostaustralische Zeit", "Australia/Sydney" },
2823 
2824         { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
2825         { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
2826         { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
2827         { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "Ostaustralische Sommerzeit", "+11:00" },
2828         { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
2829         { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
2830         { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
2831         { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "Ostaustralische Normalzeit", "+10:00" },
2832         { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "Sydney Zeit", "Australia/Sydney" },
2833         { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "Ostaustralische Zeit", "Australia/Sydney" },
2834 
2835         { "de", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
2836         { "de", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
2837         { "de", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
2838         { "de", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "Mittlere Greenwich-Zeit", "+0:00" },
2839         { "de", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
2840         { "de", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
2841         { "de", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
2842         { "de", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "Britische Sommerzeit", "+1:00" },
2843         { "de", "Europe/London", "2004-07-15T00:00:00Z", "v", "Vereinigtes K\\u00f6nigreich Zeit", "Europe/London" },
2844         { "de", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "Vereinigtes K\\u00f6nigreich Zeit", "Europe/London" },
2845 
2846         { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2847         { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2848         { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2849         { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
2850         { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2851         { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2852         { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2853         { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
2854         { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
2855         { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
2856 
2857         // JB#5150
2858         { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
2859         { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
2860         { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
2861         { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "Indische Normalzeit", "+5:30" },
2862         { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
2863         { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
2864         { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
2865         { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "Indische Normalzeit", "+5:30" },
2866         { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "Indien Zeit", "Asia/Calcutta" },
2867         { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "Indische Normalzeit", "Asia/Calcutta" },
2868 
2869         // ==========
2870 
2871         { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
2872         { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
2873         { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "America/Los_Angeles" },
2874         { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\\u5317\\u7f8e\\u592a\\u5e73\\u6d0b\\u6807\\u51c6\\u65f6\\u95f4", "America/Los_Angeles" },
2875         { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
2876         { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
2877         { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "America/Los_Angeles" },
2878         { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\\u5317\\u7f8e\\u592a\\u5e73\\u6d0b\\u590f\\u4ee4\\u65f6\\u95f4", "America/Los_Angeles" },
2879     // icu zh.txt has exemplar city for this time zone
2880         { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u6D1B\\u6749\\u77F6\\u65F6\\u95F4", "America/Los_Angeles" },
2881         { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\\u5317\\u7f8e\\u592a\\u5e73\\u6d0b\\u65f6\\u95f4", "America/Los_Angeles" },
2882 
2883         { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2884         { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2885         { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2886         { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "-3:00" },
2887         { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2888         { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2889         { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2890         { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "-3:00" },
2891         { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u5E03\\u5B9C\\u8BFA\\u65AF\\u827E\\u5229\\u65AF\\u65F6\\u95F4", "America/Buenos_Aires" },
2892         { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "America/Buenos_Aires" },
2893 
2894         { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2895         { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2896         { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2897         { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "-3:00" },
2898         { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2899         { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2900         { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2901         { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "-3:00" },
2902         { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u5E03\\u5B9C\\u8BFA\\u65AF\\u827E\\u5229\\u65AF\\u65F6\\u95F4", "America/Buenos_Aires" },
2903         { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "America/Buenos_Aires" },
2904 
2905         { "zh", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
2906         { "zh", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
2907         { "zh", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
2908         { "zh", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\\u53e4\\u5df4\\u6807\\u51c6\\u65f6\\u95f4", "-5:00" },
2909         { "zh", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
2910         { "zh", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
2911         { "zh", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
2912         { "zh", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "\\u53e4\\u5df4\\u590f\\u4ee4\\u65f6\\u95f4", "-4:00" },
2913         { "zh", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u53e4\\u5df4\\u65f6\\u95f4", "America/Havana" },
2914         { "zh", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u53e4\\u5df4\\u65f6\\u95f4", "America/Havana" },
2915 
2916         { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
2917         { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
2918         { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
2919         { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u590f\\u4ee4\\u65f6\\u95f4", "+11:00" },
2920         { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
2921         { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
2922         { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
2923         { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u6807\\u51c6\\u65f6\\u95f4", "+10:00" },
2924     // icu zh.txt does not have info for this time zone
2925         { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u6089\\u5C3C\\u65F6\\u95F4", "Australia/Sydney" },
2926         { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u65f6\\u95f4", "Australia/Sydney" },
2927 
2928         { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
2929         { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
2930         { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
2931         { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u590f\\u4ee4\\u65f6\\u95f4", "+11:00" },
2932         { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
2933         { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
2934         { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
2935         { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u6807\\u51c6\\u65f6\\u95f4", "+10:00" },
2936         { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u6089\\u5C3C\\u65F6\\u95F4", "Australia/Sydney" },
2937         { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u65f6\\u95f4", "Australia/Sydney" },
2938 
2939         { "zh", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
2940         { "zh", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
2941         { "zh", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
2942         { "zh", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
2943         { "zh", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
2944         { "zh", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u683C\\u6797\\u5C3C\\u6CBB\\u6807\\u51C6\\u65F6\\u95F4", "+0:00" },
2945         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
2946         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
2947         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
2948         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\\u82f1\\u56fd\\u590f\\u4ee4\\u65f6\\u95f4", "+1:00" },
2949         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u82f1\\u56fd\\u65f6\\u95f4", "Europe/London" },
2950         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u82f1\\u56fd\\u65f6\\u95f4", "Europe/London" },
2951         { "zh", "Europe/London", "2004-07-15T00:00:00Z", "VVVV", "\\u82f1\\u56fd\\u65f6\\u95f4", "Europe/London" },
2952 
2953         { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2954         { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2955         { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2956         { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
2957         { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2958         { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2959         { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2960         { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
2961         { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
2962         { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
2963 
2964         // JB#5150
2965         { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
2966         { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
2967         { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
2968         { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\\u5370\\u5ea6\\u65f6\\u95f4", "+5:30" },
2969         { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
2970         { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
2971         { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
2972         { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\\u5370\\u5ea6\\u65f6\\u95f4", "+5:30" },
2973         { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u5370\\u5ea6\\u65f6\\u95f4", "Asia/Calcutta" },
2974         { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u5370\\u5ea6\\u65f6\\u95f4", "Asia/Calcutta" },
2975 
2976         // ==========
2977 
2978         { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
2979         { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
2980         { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "-8:00" },
2981         { "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" },
2982         { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
2983         { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
2984         { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "-7:00" },
2985         { "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" },
2986         { "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" },
2987         { "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" },
2988 
2989         { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2990         { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2991         { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2992         { "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" },
2993         { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2994         { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2995         { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2996         { "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" },
2997         { "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" },
2998         { "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" },
2999 
3000         { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3001         { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3002         { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3003         { "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" },
3004         { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3005         { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3006         { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3007         { "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" },
3008         { "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" },
3009         { "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" },
3010 
3011         { "hi", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
3012         { "hi", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
3013         { "hi", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
3014         { "hi", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\\u0915\\u094d\\u092f\\u0942\\u092c\\u093e \\u092e\\u093e\\u0928\\u0915 \\u0938\\u092e\\u092f", "-5:00" },
3015         { "hi", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
3016         { "hi", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
3017         { "hi", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
3018         { "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" },
3019         { "hi", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u0915\\u094d\\u092f\\u0942\\u092c\\u093e \\u0938\\u092E\\u092F", "America/Havana" },
3020         { "hi", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u0915\\u094d\\u092f\\u0942\\u092c\\u093e \\u0938\\u092e\\u092f", "America/Havana" },
3021 
3022         { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3023         { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
3024         { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
3025         { "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" },
3026         { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3027         { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
3028         { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
3029         { "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" },
3030         { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u0938\\u093F\\u0921\\u0928\\u0940 \\u0938\\u092E\\u092F", "Australia/Sydney" },
3031         { "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" },
3032 
3033         { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3034         { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
3035         { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
3036         { "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" },
3037         { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3038         { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
3039         { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
3040         { "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" },
3041         { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u0938\\u093F\\u0921\\u0928\\u0940 \\u0938\\u092E\\u092F", "Australia/Sydney" },
3042         { "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" },
3043 
3044         { "hi", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
3045         { "hi", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
3046         { "hi", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
3047         { "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" },
3048         { "hi", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
3049         { "hi", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
3050         { "hi", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
3051         { "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" },
3052         { "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" },
3053         { "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" },
3054 
3055         { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3056         { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3057         { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3058         { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3059         { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3060         { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3061         { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3062         { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3063         { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
3064         { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
3065 
3066         { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
3067         { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
3068         { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "IST", "+5:30" },
3069         { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\\u092D\\u093E\\u0930\\u0924\\u0940\\u092F \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "+5:30" },
3070         { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
3071         { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
3072         { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "IST", "+05:30" },
3073         { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\\u092D\\u093E\\u0930\\u0924\\u0940\\u092F \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "+5:30" },
3074         { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "IST", "Asia/Calcutta" },
3075         { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u092D\\u093E\\u0930\\u0924\\u0940\\u092F \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "Asia/Calcutta" },
3076 
3077         // ==========
3078 
3079         { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
3080         { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-08:00", "-8:00" },
3081         { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-8", "America/Los_Angeles" },
3082         { "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" },
3083         { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
3084         { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-07:00", "-7:00" },
3085         { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-7", "America/Los_Angeles" },
3086         { "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" },
3087     // icu bg.txt has exemplar city for this time zone
3088         { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u041B\\u043E\\u0441 \\u0410\\u043D\\u0434\\u0436\\u0435\\u043B\\u0438\\u0441", "America/Los_Angeles" },
3089         { "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" },
3090         { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "VVVV", "\\u041B\\u043E\\u0441 \\u0410\\u043D\\u0434\\u0436\\u0435\\u043B\\u0438\\u0441", "America/Los_Angeles" },
3091 
3092         { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3093         { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3094         { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3095         { "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" },
3096         { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3097         { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3098         { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3099         { "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" },
3100         { "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" },
3101         { "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" },
3102 
3103         { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3104         { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3105         { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3106         { "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" },
3107         { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3108         { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3109         { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3110         { "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" },
3111     // icu bg.txt does not have info for this time zone
3112         { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u0411\\u0443\\u0435\\u043D\\u043E\\u0441 \\u0410\\u0439\\u0440\\u0435\\u0441", "America/Buenos_Aires" },
3113         { "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" },
3114 
3115         { "bg", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
3116         { "bg", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-05:00", "-5:00" },
3117         { "bg", "America/Havana", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-5", "-5:00" },
3118         { "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" },
3119         { "bg", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
3120         { "bg", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-04:00", "-4:00" },
3121         { "bg", "America/Havana", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-4", "-4:00" },
3122         { "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" },
3123         { "bg", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u041a\\u0443\\u0431\\u0430", "America/Havana" },
3124         { "bg", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u041a\\u0443\\u0431\\u0438\\u043d\\u0441\\u043a\\u043e \\u0432\\u0440\\u0435\\u043C\\u0435", "America/Havana" },
3125 
3126         { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3127         { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+11:00", "+11:00" },
3128         { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+11", "+11:00" },
3129         { "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" },
3130         { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3131         { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+10:00", "+10:00" },
3132         { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+10", "+10:00" },
3133         { "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" },
3134         { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u0421\\u0438\\u0434\\u043D\\u0438", "Australia/Sydney" },
3135         { "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" },
3136 
3137         { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3138         { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+11:00", "+11:00" },
3139         { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+11", "+11:00" },
3140         { "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" },
3141         { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3142         { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+10:00", "+10:00" },
3143         { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+10", "+10:00" },
3144         { "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" },
3145         { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u0421\\u0438\\u0434\\u043D\\u0438", "Australia/Sydney" },
3146         { "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" },
3147 
3148         { "bg", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
3149         { "bg", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447", "+0:00" },
3150         { "bg", "Europe/London", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447", "+0:00" },
3151         { "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" },
3152         { "bg", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
3153         { "bg", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+01:00", "+1:00" },
3154         { "bg", "Europe/London", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+1", "+1:00" },
3155         { "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" },
3156         { "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" },
3157         { "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" },
3158 
3159         { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3160         { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3161         { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3162         { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3163         { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3164         { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3165         { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3166         { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3167         { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3168         { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3169 
3170         // JB#5150
3171         { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
3172         { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+05:30", "+5:30" },
3173         { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+5:30", "+5:30" },
3174         { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\\u0418\\u043D\\u0434\\u0438\\u0439\\u0441\\u043A\\u043E \\u0432\\u0440\\u0435\\u043c\\u0435", "+5:30" },
3175         { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
3176         { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+05:30", "+5:30" },
3177         { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+5:30", "+05:30" },
3178         { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\\u0418\\u043D\\u0434\\u0438\\u0439\\u0441\\u043A\\u043E \\u0432\\u0440\\u0435\\u043c\\u0435", "+5:30" },
3179         { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u0418\\u043D\\u0434\\u0438\\u044F", "Asia/Calcutta" },
3180         { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u0418\\u043D\\u0434\\u0438\\u0439\\u0441\\u043A\\u043E \\u0432\\u0440\\u0435\\u043c\\u0435", "Asia/Calcutta" },
3181     // ==========
3182 
3183         { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
3184         { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
3185         { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "America/Los_Angeles" },
3186         { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\\u30a2\\u30e1\\u30ea\\u30ab\\u592a\\u5e73\\u6d0b\\u6a19\\u6e96\\u6642", "America/Los_Angeles" },
3187         { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-700" },
3188         { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
3189         { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "America/Los_Angeles" },
3190         { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\\u30a2\\u30e1\\u30ea\\u30ab\\u592a\\u5e73\\u6d0b\\u590f\\u6642\\u9593", "America/Los_Angeles" },
3191     // icu ja.txt has exemplar city for this time zone
3192         { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u30ED\\u30B5\\u30F3\\u30BC\\u30EB\\u30B9\\u6642\\u9593", "America/Los_Angeles" },
3193         { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\\u30A2\\u30E1\\u30EA\\u30AB\\u592A\\u5e73\\u6D0B\\u6642\\u9593", "America/Los_Angeles" },
3194         { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "VVVV", "\\u30ED\\u30B5\\u30F3\\u30BC\\u30EB\\u30B9\\u6642\\u9593", "America/Los_Angeles" },
3195 
3196         { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3197         { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3198         { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3199         { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "-3:00" },
3200         { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3201         { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3202         { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3203         { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "-3:00" },
3204     // icu ja.txt does not have info for this time zone
3205         { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u30D6\\u30A8\\u30CE\\u30B9\\u30A2\\u30A4\\u30EC\\u30B9\\u6642\\u9593", "America/Buenos_Aires" },
3206         { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "America/Buenos_Aires" },
3207 
3208         { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3209         { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3210         { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3211         { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "-3:00" },
3212         { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3213         { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3214         { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3215         { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "-3:00" },
3216         { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u30D6\\u30A8\\u30CE\\u30B9\\u30A2\\u30A4\\u30EC\\u30B9\\u6642\\u9593", "America/Buenos_Aires" },
3217         { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "America/Buenos_Aires" },
3218 
3219         { "ja", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
3220         { "ja", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
3221         { "ja", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
3222         { "ja", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\\u30AD\\u30E5\\u30FC\\u30D0\\u6A19\\u6E96\\u6642", "-5:00" },
3223         { "ja", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
3224         { "ja", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
3225         { "ja", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
3226         { "ja", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "\\u30AD\\u30E5\\u30FC\\u30D0\\u590F\\u6642\\u9593", "-4:00" },
3227         { "ja", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u30ad\\u30e5\\u30fc\\u30d0\\u6642\\u9593", "America/Havana" },
3228         { "ja", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u30ad\\u30e5\\u30fc\\u30d0\\u6642\\u9593", "America/Havana" },
3229 
3230         { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3231         { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
3232         { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
3233         { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u590F\\u6642\\u9593", "+11:00" },
3234         { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3235         { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
3236         { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
3237         { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u6A19\\u6E96\\u6642", "+10:00" },
3238     // icu ja.txt does not have info for this time zone
3239         { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u30B7\\u30C9\\u30CB\\u30FC\\u6642\\u9593", "Australia/Sydney" },
3240         { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u6642\\u9593", "Australia/Sydney" },
3241 
3242         { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3243         { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
3244         { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
3245         { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u590F\\u6642\\u9593", "+11:00" },
3246         { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3247         { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
3248         { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
3249         { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u6A19\\u6E96\\u6642", "+10:00" },
3250         { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u30B7\\u30C9\\u30CB\\u30FC\\u6642\\u9593", "Australia/Sydney" },
3251         { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u6642\\u9593", "Australia/Sydney" },
3252 
3253         { "ja", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
3254         { "ja", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
3255         { "ja", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
3256         { "ja", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u30B0\\u30EA\\u30CB\\u30C3\\u30B8\\u6A19\\u6E96\\u6642", "+0:00" },
3257         { "ja", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
3258         { "ja", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
3259         { "ja", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
3260         { "ja", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\\u82f1\\u56fd\\u590f\\u6642\\u9593", "+1:00" },
3261         { "ja", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\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         { "ja", "Europe/London", "2004-07-15T00:00:00Z", "VVVV", "\\u30a4\\u30ae\\u30ea\\u30b9\\u6642\\u9593", "Europe/London" },
3264 
3265         { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3266         { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3267         { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3268         { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3269         { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3270         { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3271         { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3272         { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3273         { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
3274         { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
3275 
3276         // JB#5150
3277         { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
3278         { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
3279         { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
3280         { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\\u30A4\\u30F3\\u30C9\\u6A19\\u6E96\\u6642", "+5:30" },
3281         { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
3282         { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
3283         { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
3284         { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\\u30A4\\u30F3\\u30C9\\u6A19\\u6E96\\u6642", "+5:30" },
3285         { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u30A4\\u30F3\\u30C9\\u6642\\u9593", "Asia/Calcutta" },
3286         { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u30A4\\u30F3\\u30C9\\u6A19\\u6E96\\u6642", "Asia/Calcutta" },
3287 
3288     // ==========
3289 
3290         { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
3291         { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
3292         { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "-8:00" },
3293         { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "GMT-08:00", "-8:00" },
3294         { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
3295         { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
3296         { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "-7:00" },
3297         { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "GMT-07:00", "-7:00" },
3298         { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "Los Angeles", "America/Los_Angeles" },
3299         { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "Los Angeles", "America/Los_Angeles" },
3300 
3301         { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3302         { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3303         { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3304         { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3305         { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3306         { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3307         { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3308         { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3309         { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires", "America/Buenos_Aires" },
3310         { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Buenos Aires", "America/Buenos_Aires" },
3311 
3312         { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3313         { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3314         { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3315         { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3316         { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3317         { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3318         { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3319         { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3320         { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires", "America/Buenos_Aires" },
3321         { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Buenos Aires", "America/Buenos_Aires" },
3322 
3323         { "ti", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
3324         { "ti", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
3325         { "ti", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
3326         { "ti", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "GMT-05:00", "-5:00" },
3327         { "ti", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
3328         { "ti", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
3329         { "ti", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
3330         { "ti", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "GMT-04:00", "-4:00" },
3331         { "ti", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u12A9\\u1263", "America/Havana" },
3332         { "ti", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u12A9\\u1263", "America/Havana" },
3333 
3334         { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3335         { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
3336         { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
3337         { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "GMT+11:00", "+11:00" },
3338         { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3339         { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
3340         { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
3341         { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "GMT+10:00", "+10:00" },
3342         { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "Sydney", "Australia/Sydney" },
3343         { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "Sydney", "Australia/Sydney" },
3344 
3345         { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3346         { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
3347         { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
3348         { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "GMT+11:00", "+11:00" },
3349         { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3350         { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
3351         { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
3352         { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "GMT+10:00", "+10:00" },
3353         { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "Sydney", "Australia/Sydney" },
3354         { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "Sydney", "Australia/Sydney" },
3355 
3356         { "ti", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
3357         { "ti", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
3358         { "ti", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
3359         { "ti", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "GMT", "+0:00" },
3360         { "ti", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
3361         { "ti", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
3362         { "ti", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
3363         { "ti", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "British Summer Time", "+1:00" },
3364         { "ti", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u12A5\\u1295\\u130D\\u120A\\u12DD", "Europe/London" },
3365         { "ti", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u12A5\\u1295\\u130D\\u120A\\u12DD", "Europe/London" },
3366 
3367         { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3368         { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3369         { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3370         { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3371         { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3372         { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3373         { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3374         { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3375         { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
3376         { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
3377 
3378         // JB#5150
3379         { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
3380         { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
3381         { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
3382         { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "GMT+05:30", "+5:30" },
3383         { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
3384         { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
3385         { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
3386         { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "GMT+05:30", "+5:30" },
3387         { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u1205\\u1295\\u12F2", "Alna/Calcutta" },
3388         { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u1205\\u1295\\u12F2", "Asia/Calcutta" },
3389 
3390         // Ticket#8589 Partial location name to use country name if the zone is the golden
3391         // zone for the time zone's country.
3392         { "en_MX", "America/Chicago", "1995-07-15T00:00:00Z", "vvvv", "Central Time (United States)", "America/Chicago"},
3393 
3394         // Tests proper handling of time zones that should have empty sets when inherited from the parent.
3395         // For example, en_GB understands CET as Central European Time, but en_HK, which inherits from en_GB
3396         // does not
3397         { "en_GB", "Europe/Paris", "2004-01-15T00:00:00Z", "zzzz", "Central European Standard Time", "+1:00"},
3398         { "en_GB", "Europe/Paris", "2004-07-15T00:00:00Z", "zzzz", "Central European Summer Time", "+2:00"},
3399         { "en_GB", "Europe/Paris", "2004-01-15T00:00:00Z", "z", "CET", "+1:00"},
3400         { "en_GB", "Europe/Paris", "2004-07-15T00:00:00Z", "z", "CEST", "+2:00"},
3401         { "en_HK", "Europe/Paris", "2004-01-15T00:00:00Z", "zzzz", "Central European Standard Time", "+1:00"},
3402         { "en_HK", "Europe/Paris", "2004-07-15T00:00:00Z", "zzzz", "Central European Summer Time", "+2:00"},
3403         { "en_HK", "Europe/Paris", "2004-01-15T00:00:00Z", "z", "GMT+1", "+1:00"},
3404         { "en_HK", "Europe/Paris", "2004-07-15T00:00:00Z", "z", "GMT+2", "+2:00"},
3405 
3406         { NULL, NULL, NULL, NULL, NULL, NULL },
3407     };
3408 
3409     UErrorCode status = U_ZERO_ERROR;
3410     LocalPointer<Calendar> cal(GregorianCalendar::createInstance(status));
3411     if (failure(status, "GregorianCalendar::createInstance", TRUE)) return;
3412     SimpleDateFormat testfmt(UnicodeString("yyyy-MM-dd'T'HH:mm:ss'Z'"), status);
3413     if (failure(status, "SimpleDateFormat constructor", TRUE)) return;
3414     testfmt.setTimeZone(*TimeZone::getGMT());
3415 
3416     for (int i = 0; fallbackTests[i][0]; i++) {
3417         const char **testLine = fallbackTests[i];
3418         UnicodeString info[5];
3419         for ( int j = 0 ; j < 5 ; j++ ) {
3420             info[j] = UnicodeString(testLine[j], -1, US_INV);
3421         }
3422         info[4] = info[4].unescape();
3423         logln("%s;%s;%s;%s", testLine[0], testLine[1], testLine[2], testLine[3]);
3424 
3425         TimeZone *tz = TimeZone::createTimeZone(info[1]);
3426 
3427         UDate d = testfmt.parse(testLine[2], status);
3428         cal->setTime(d, status);
3429         if (U_FAILURE(status)) {
3430             errln(UnicodeString("Failed to set date: ") + testLine[2]);
3431         }
3432 
3433         SimpleDateFormat fmt(info[3], Locale(testLine[0]),status);
3434         ASSERT_OK(status);
3435         cal->adoptTimeZone(tz);
3436         UnicodeString result;
3437         FieldPosition pos(FieldPosition::DONT_CARE);
3438         fmt.format(*cal.getAlias(), result,pos);
3439         if (result != info[4]) {
3440             errln(info[0] + ";" + info[1] + ";" + info[2] + ";" + info[3] + " expected: '" +
3441                   info[4] + "' but got: '" + result + "'");
3442         }
3443     }
3444 }
3445 
TestTimeZoneInLocale()3446 void DateFormatTest::TestTimeZoneInLocale()
3447 {
3448     const char *tests[][3]  = {
3449         { "en-u-tz-usden",                     "America/Denver",             "gregorian" },
3450         { "es-u-tz-usden",                     "America/Denver",             "gregorian" },
3451         { "ms-u-tz-mykul",                     "Asia/Kuala_Lumpur",          "gregorian" },
3452         { "zh-u-tz-mykul",                     "Asia/Kuala_Lumpur",          "gregorian" },
3453         { "fr-u-ca-buddhist-tz-phmnl",         "Asia/Manila",                "buddhist" },
3454         { "th-u-ca-chinese-tz-gblon",          "Europe/London",              "chinese" },
3455         { "de-u-ca-coptic-tz-ciabj",           "Africa/Abidjan",             "coptic" },
3456         { "ja-u-ca-dangi-tz-hkhkg",            "Asia/Hong_Kong",             "dangi" },
3457         { "da-u-ca-ethioaa-tz-ruunera",        "Asia/Ust-Nera",              "ethiopic-amete-alem" },
3458         { "ko-u-ca-ethiopic-tz-cvrai",         "Atlantic/Cape_Verde",        "ethiopic" },
3459         { "fil-u-ca-gregory-tz-aubne",         "Australia/Brisbane",         "gregorian" },
3460         { "fa-u-ca-hebrew-tz-brrbr",           "America/Rio_Branco",         "hebrew" },
3461         { "gr-u-ca-indian-tz-lccas",           "America/St_Lucia",           "indian" },
3462         { "or-u-ca-islamic-tz-cayyn",          "America/Swift_Current",      "islamic" },
3463         { "my-u-ca-islamic-umalqura-tz-kzala", "Asia/Almaty",                "islamic-umalqura" },
3464         { "lo-u-ca-islamic-tbla-tz-bmbda",     "Atlantic/Bermuda",           "islamic-tbla" },
3465         { "km-u-ca-islamic-civil-tz-aqplm",    "Antarctica/Palmer",          "islamic-civil" },
3466         { "kk-u-ca-islamic-rgsa-tz-usanc",     "America/Anchorage",          "islamic" },
3467         { "ar-u-ca-iso8601-tz-bjptn",          "Africa/Porto-Novo",          "gregorian" },
3468         { "he-u-ca-japanese-tz-tzdar",         "Africa/Dar_es_Salaam",       "japanese" },
3469         { "bs-u-ca-persian-tz-etadd",          "Africa/Addis_Ababa",         "persian" },
3470         { "it-u-ca-roc-tz-aruaq",              "America/Argentina/San_Juan", "roc" },
3471     };
3472 
3473     for (int32_t i = 0; i < UPRV_LENGTHOF(tests); ++i) {
3474         UErrorCode status = U_ZERO_ERROR;
3475         const char **testLine = tests[i];
3476         Locale locale(testLine[0]);
3477         UnicodeString expectedTimezone(testLine[1], -1, US_INV);
3478         UnicodeString actual;
3479 
3480         SimpleDateFormat smptfmt("Z", locale, status);
3481         ASSERT_OK(status);
3482         assertEquals("TimeZone from SimpleDateFormat constructor",
3483                      expectedTimezone, smptfmt.getTimeZone().getID(actual));
3484         assertEquals("Calendar from SimpleDateFormat constructor",
3485                      testLine[2], smptfmt.getCalendar()->getType());
3486 
3487         LocalPointer<DateFormat> datefmt(
3488                 DateFormat::createDateInstance(DateFormat::kDefault, locale));
3489         if (datefmt == nullptr) {
3490             dataerrln("Error calling DateFormat::createDateInstance()");
3491             return;
3492         }
3493         assertEquals("TimeZone from DateFormat::createDateInstance",
3494                      expectedTimezone, datefmt->getTimeZone().getID(actual));
3495         assertEquals("Calendar from DateFormat::createDateInstance",
3496                      testLine[2], datefmt->getCalendar()->getType());
3497         LocalPointer<DateFormat> timefmt(
3498                 DateFormat::createTimeInstance(DateFormat::kDefault, locale));
3499         if (timefmt == nullptr) {
3500             dataerrln("Error calling DateFormat::createTimeInstance()");
3501             return;
3502         }
3503         assertEquals("TimeZone from TimeFormat::createTimeInstance",
3504                      expectedTimezone, timefmt->getTimeZone().getID(actual));
3505         assertEquals("Calendar from DateFormat::createTimeInstance",
3506                      testLine[2], timefmt->getCalendar()->getType());
3507 
3508         LocalPointer<DateFormat> datetimefmt(
3509                 DateFormat::createDateTimeInstance(
3510                     DateFormat::kDefault, DateFormat::kDefault, locale));
3511         if (datetimefmt == nullptr) {
3512             dataerrln("Error calling DateFormat::createDateTimeInstance()");
3513             return;
3514         }
3515         assertEquals("TimeZone from DateTimeFormat::createDateTimeInstance",
3516                      expectedTimezone, datetimefmt->getTimeZone().getID(actual));
3517         assertEquals("Calendar from DateFormat::createDateTimeInstance",
3518                      testLine[2], datetimefmt->getCalendar()->getType());
3519     }
3520 }
3521 
TestRoundtripWithCalendar(void)3522 void DateFormatTest::TestRoundtripWithCalendar(void) {
3523     UErrorCode status = U_ZERO_ERROR;
3524 
3525     TimeZone *tz = TimeZone::createTimeZone("Europe/Paris");
3526     TimeZone *gmt = TimeZone::createTimeZone("Etc/GMT");
3527 
3528     Calendar *calendars[] = {
3529         Calendar::createInstance(*tz, Locale("und@calendar=gregorian"), status),
3530         Calendar::createInstance(*tz, Locale("und@calendar=buddhist"), status),
3531 //        Calendar::createInstance(*tz, Locale("und@calendar=hebrew"), status),
3532         Calendar::createInstance(*tz, Locale("und@calendar=islamic"), status),
3533         Calendar::createInstance(*tz, Locale("und@calendar=japanese"), status),
3534         NULL
3535     };
3536     if (U_FAILURE(status)) {
3537         dataerrln("Failed to initialize calendars: %s", u_errorName(status));
3538         for (int i = 0; calendars[i] != NULL; i++) {
3539             delete calendars[i];
3540         }
3541         return;
3542     }
3543 
3544     //FIXME The formatters commented out below are currently failing because of
3545     // the calendar calculation problem reported by #6691
3546 
3547     // The order of test formatters must match the order of calendars above.
3548     DateFormat *formatters[] = {
3549         DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("en_US")), //calendar=gregorian
3550         DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("th_TH")), //calendar=buddhist
3551 //        DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("he_IL@calendar=hebrew")),
3552         DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("ar_EG@calendar=islamic")),
3553 //        DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("ja_JP@calendar=japanese")),
3554         NULL
3555     };
3556 
3557     UDate d = Calendar::getNow();
3558     UnicodeString buf;
3559     FieldPosition fpos;
3560     ParsePosition ppos;
3561 
3562     for (int i = 0; formatters[i] != NULL; i++) {
3563         buf.remove();
3564         fpos.setBeginIndex(0);
3565         fpos.setEndIndex(0);
3566         calendars[i]->setTime(d, status);
3567 
3568         // Normal case output - the given calendar matches the calendar
3569         // used by the formatter
3570         formatters[i]->format(*calendars[i], buf, fpos);
3571         UnicodeString refStr(buf);
3572 
3573         for (int j = 0; calendars[j] != NULL; j++) {
3574             if (j == i) {
3575                 continue;
3576             }
3577             buf.remove();
3578             fpos.setBeginIndex(0);
3579             fpos.setEndIndex(0);
3580             calendars[j]->setTime(d, status);
3581 
3582             // Even the different calendar type is specified,
3583             // we should get the same result.
3584             formatters[i]->format(*calendars[j], buf, fpos);
3585             if (refStr != buf) {
3586                 errln((UnicodeString)"FAIL: Different format result with a different calendar for the same time -"
3587                         + "\n Reference calendar type=" + calendars[i]->getType()
3588                         + "\n Another calendar type=" + calendars[j]->getType()
3589                         + "\n Expected result=" + refStr
3590                         + "\n Actual result=" + buf);
3591             }
3592         }
3593 
3594         calendars[i]->setTimeZone(*gmt);
3595         calendars[i]->clear();
3596         ppos.setErrorIndex(-1);
3597         ppos.setIndex(0);
3598 
3599         // Normal case parse result - the given calendar matches the calendar
3600         // used by the formatter
3601         formatters[i]->parse(refStr, *calendars[i], ppos);
3602 
3603         for (int j = 0; calendars[j] != NULL; j++) {
3604             if (j == i) {
3605                 continue;
3606             }
3607             calendars[j]->setTimeZone(*gmt);
3608             calendars[j]->clear();
3609             ppos.setErrorIndex(-1);
3610             ppos.setIndex(0);
3611 
3612             // Even the different calendar type is specified,
3613             // we should get the same time and time zone.
3614             formatters[i]->parse(refStr, *calendars[j], ppos);
3615             if (calendars[i]->getTime(status) != calendars[j]->getTime(status)
3616                 || calendars[i]->getTimeZone() != calendars[j]->getTimeZone()) {
3617                 UnicodeString tzid;
3618                 errln((UnicodeString)"FAIL: Different parse result with a different calendar for the same string -"
3619                         + "\n Reference calendar type=" + calendars[i]->getType()
3620                         + "\n Another calendar type=" + calendars[j]->getType()
3621                         + "\n Date string=" + refStr
3622                         + "\n Expected time=" + calendars[i]->getTime(status)
3623                         + "\n Expected time zone=" + calendars[i]->getTimeZone().getID(tzid)
3624                         + "\n Actual time=" + calendars[j]->getTime(status)
3625                         + "\n Actual time zone=" + calendars[j]->getTimeZone().getID(tzid));
3626             }
3627         }
3628         if (U_FAILURE(status)) {
3629             errln((UnicodeString)"FAIL: " + u_errorName(status));
3630             break;
3631         }
3632     }
3633 
3634     delete tz;
3635     delete gmt;
3636     for (int i = 0; calendars[i] != NULL; i++) {
3637         delete calendars[i];
3638     }
3639     for (int i = 0; formatters[i] != NULL; i++) {
3640         delete formatters[i];
3641     }
3642 }
3643 
3644 /*
3645 void DateFormatTest::TestRelativeError(void)
3646 {
3647     UErrorCode status;
3648     Locale en("en");
3649 
3650     DateFormat *en_reltime_reldate =         DateFormat::createDateTimeInstance(DateFormat::kFullRelative,DateFormat::kFullRelative,en);
3651     if(en_reltime_reldate == NULL) {
3652         logln("PASS: rel date/rel time failed");
3653     } else {
3654         errln("FAIL: rel date/rel time created, should have failed.");
3655         delete en_reltime_reldate;
3656     }
3657 }
3658 
3659 void DateFormatTest::TestRelativeOther(void)
3660 {
3661     logln("Nothing in this test. When we get more data from CLDR, put in some tests of -2, +2, etc. ");
3662 }
3663 */
3664 
Test6338(void)3665 void DateFormatTest::Test6338(void)
3666 {
3667     UErrorCode status = U_ZERO_ERROR;
3668 
3669     SimpleDateFormat fmt1(UnicodeString(u"y-M-d"), Locale("ar"), status);
3670     if (failure(status, "new SimpleDateFormat", TRUE)) return;
3671 
3672     UDate dt1 = date(2008-1900, UCAL_JUNE, 10, 12, 00);
3673     UnicodeString str1;
3674     str1 = fmt1.format(dt1, str1);
3675     logln(str1);
3676 
3677     UDate dt11 = fmt1.parse(str1, status);
3678     failure(status, "fmt->parse");
3679 
3680     UnicodeString str11;
3681     str11 = fmt1.format(dt11, str11);
3682     logln(str11);
3683 
3684     if (str1 != str11) {
3685         errln((UnicodeString)"FAIL: Different dates str1:" + str1
3686             + " str2:" + str11);
3687     }
3688 
3689     /////////////////
3690 
3691     status = U_ZERO_ERROR;
3692     SimpleDateFormat fmt2(UnicodeString(u"y M d"), Locale("ar"), status);
3693     failure(status, "new SimpleDateFormat");
3694 
3695     UDate dt2 = date(2008-1900, UCAL_JUNE, 10, 12, 00);
3696     UnicodeString str2;
3697     str2 = fmt2.format(dt2, str2);
3698     logln(str2);
3699 
3700     UDate dt22 = fmt2.parse(str2, status);
3701     failure(status, "fmt->parse");
3702 
3703     UnicodeString str22;
3704     str22 = fmt2.format(dt22, str22);
3705     logln(str22);
3706 
3707     if (str2 != str22) {
3708         errln((UnicodeString)"FAIL: Different dates str1:" + str2
3709             + " str2:" + str22);
3710     }
3711 
3712     /////////////////
3713 
3714     status = U_ZERO_ERROR;
3715     SimpleDateFormat fmt3(UnicodeString("y-M-d"), Locale("en-us"), status);
3716     failure(status, "new SimpleDateFormat");
3717 
3718     UDate dt3 = date(2008-1900, UCAL_JUNE, 10, 12, 00);
3719     UnicodeString str3;
3720     str3 = fmt3.format(dt3, str3);
3721     logln(str3);
3722 
3723     UDate dt33 = fmt3.parse(str3, status);
3724     failure(status, "fmt->parse");
3725 
3726     UnicodeString str33;
3727     str33 = fmt3.format(dt33, str33);
3728     logln(str33);
3729 
3730     if (str3 != str33) {
3731         errln((UnicodeString)"FAIL: Different dates str1:" + str3
3732             + " str2:" + str33);
3733     }
3734 
3735     /////////////////
3736 
3737     status = U_ZERO_ERROR;
3738     SimpleDateFormat fmt4(UnicodeString("y M  d"), Locale("en-us"), status);
3739     failure(status, "new SimpleDateFormat");
3740 
3741     UDate dt4 = date(2008-1900, UCAL_JUNE, 10, 12, 00);
3742     UnicodeString str4;
3743     str4 = fmt4.format(dt4, str4);
3744     logln(str4);
3745 
3746     UDate dt44 = fmt4.parse(str4, status);
3747     failure(status, "fmt->parse");
3748 
3749     UnicodeString str44;
3750     str44 = fmt4.format(dt44, str44);
3751     logln(str44);
3752 
3753     if (str4 != str44) {
3754         errln((UnicodeString)"FAIL: Different dates str1:" + str4
3755             + " str2:" + str44);
3756     }
3757 
3758 }
3759 
Test6726(void)3760 void DateFormatTest::Test6726(void)
3761 {
3762     // status
3763 //    UErrorCode status = U_ZERO_ERROR;
3764 
3765     // fmtf, fmtl, fmtm, fmts;
3766     UnicodeString strf, strl, strm, strs;
3767     UDate dt = date(2008-1900, UCAL_JUNE, 10, 12, 00);
3768 
3769     Locale loc("ja");
3770     DateFormat* fmtf = DateFormat::createDateTimeInstance(DateFormat::FULL, DateFormat::FULL, loc);
3771     DateFormat* fmtl = DateFormat::createDateTimeInstance(DateFormat::LONG, DateFormat::FULL, loc);
3772     DateFormat* fmtm = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::FULL, loc);
3773     DateFormat* fmts = DateFormat::createDateTimeInstance(DateFormat::SHORT, DateFormat::FULL, loc);
3774     if (fmtf == NULL || fmtl == NULL || fmtm == NULL || fmts == NULL) {
3775         dataerrln("Unable to create DateFormat. got NULL.");
3776         /* It may not be true that if one is NULL all is NULL.  Just to be safe. */
3777         delete fmtf;
3778         delete fmtl;
3779         delete fmtm;
3780         delete fmts;
3781 
3782         return;
3783     }
3784     strf = fmtf->format(dt, strf);
3785     strl = fmtl->format(dt, strl);
3786     strm = fmtm->format(dt, strm);
3787     strs = fmts->format(dt, strs);
3788 
3789 
3790     logln("strm.charAt(10)=%04X wanted 0x20\n", strm.charAt(10));
3791     if (strm.charAt(10) != UChar(0x0020)) {
3792       errln((UnicodeString)"FAIL: Improper formatted date: " + strm );
3793     }
3794     logln("strs.charAt(10)=%04X wanted 0x20\n", strs.charAt(8));
3795     if (strs.charAt(10)  != UChar(0x0020)) {
3796         errln((UnicodeString)"FAIL: Improper formatted date: " + strs);
3797     }
3798 
3799     delete fmtf;
3800     delete fmtl;
3801     delete fmtm;
3802     delete fmts;
3803 
3804     return;
3805 }
3806 
3807 /**
3808  * Test DateFormat's parsing of default GMT variants.  See ticket#6135
3809  */
TestGMTParsing()3810 void DateFormatTest::TestGMTParsing() {
3811     const char* DATA[] = {
3812         "HH:mm:ss Z",
3813 
3814         // pattern, input, expected output (in quotes)
3815         "HH:mm:ss Z",       "10:20:30 GMT+03:00",   "10:20:30 +0300",
3816         "HH:mm:ss Z",       "10:20:30 UT-02:00",    "10:20:30 -0200",
3817         "HH:mm:ss Z",       "10:20:30 GMT",         "10:20:30 +0000",
3818         "HH:mm:ss vvvv",    "10:20:30 UT+10:00",    "10:20:30 +1000",
3819         "HH:mm:ss zzzz",    "10:20:30 UTC",         "10:20:30 +0000",   // standalone "UTC"
3820         "ZZZZ HH:mm:ss",    "UT 10:20:30",          "10:20:30 +0000",
3821         "z HH:mm:ss",       "UT+0130 10:20:30",     "10:20:30 +0130",
3822         "z HH:mm:ss",       "UTC+0130 10:20:30",    "10:20:30 +0130",
3823         // Note: GMT-1100 no longer works because of the introduction of the short
3824         // localized GMT support. Previous implementation support this level of
3825         // leniency (no separator char in localized GMT format), but the new
3826         // implementation handles GMT-11 as the legitimate short localized GMT format
3827         // and stop at there. Otherwise, roundtrip would be broken.
3828         //"HH mm Z ss",       "10 20 GMT-1100 30",    "10:20:30 -1100",
3829         "HH mm Z ss",       "10 20 GMT-11 30",    "10:20:30 -1100",
3830         "HH:mm:ssZZZZZ",    "14:25:45Z",            "14:25:45 +0000",
3831         "HH:mm:ssZZZZZ",    "15:00:00-08:00",       "15:00:00 -0800",
3832     };
3833     const int32_t DATA_len = UPRV_LENGTHOF(DATA);
3834     expectParse(DATA, DATA_len, Locale("en"));
3835 }
3836 
3837 // Test case for localized GMT format parsing
3838 // with no delimitters in offset format (Chinese locale)
Test6880()3839 void DateFormatTest::Test6880() {
3840     UErrorCode status = U_ZERO_ERROR;
3841     UDate d1, d2, dp1, dp2, dexp1, dexp2;
3842     UnicodeString s1, s2;
3843 
3844     TimeZone *tz = TimeZone::createTimeZone("Asia/Shanghai");
3845     GregorianCalendar gcal(*tz, status);
3846     if (failure(status, "construct GregorianCalendar", TRUE)) return;
3847 
3848     gcal.clear();
3849     gcal.set(1900, UCAL_JULY, 1, 12, 00);   // offset 8:05:43
3850     d1 = gcal.getTime(status);
3851 
3852     gcal.clear();
3853     gcal.set(1950, UCAL_JULY, 1, 12, 00);   // offset 8:00
3854     d2 = gcal.getTime(status);
3855 
3856     gcal.clear();
3857     gcal.set(1970, UCAL_JANUARY, 1, 12, 00);
3858     dexp2 = gcal.getTime(status);
3859     dexp1 = dexp2 - (5*60 + 43)*1000;   // subtract 5m43s
3860 
3861     if (U_FAILURE(status)) {
3862         errln("FAIL: Gregorian calendar error");
3863     }
3864 
3865     DateFormat *fmt = DateFormat::createTimeInstance(DateFormat::kFull, Locale("zh"));
3866     if (fmt == NULL) {
3867         dataerrln("Unable to create DateFormat. Got NULL.");
3868         return;
3869     }
3870     fmt->adoptTimeZone(tz);
3871 
3872     fmt->format(d1, s1);
3873     fmt->format(d2, s2);
3874 
3875     dp1 = fmt->parse(s1, status);
3876     dp2 = fmt->parse(s2, status);
3877 
3878     if (U_FAILURE(status)) {
3879         errln("FAIL: Parse failure");
3880     }
3881 
3882     if (dp1 != dexp1) {
3883         errln("FAIL: Failed to parse " + s1 + " parsed: " + dp1 + " expected: " + dexp1);
3884     }
3885     if (dp2 != dexp2) {
3886         errln("FAIL: Failed to parse " + s2 + " parsed: " + dp2 + " expected: " + dexp2);
3887     }
3888 
3889     delete fmt;
3890 }
3891 
3892 typedef struct {
3893     const char * localeStr;
3894     UBool        lenient;
3895     UBool        expectFail;
3896     UnicodeString datePattern;
3897     UnicodeString dateString;
3898 } NumAsStringItem;
3899 
TestNumberAsStringParsing()3900 void DateFormatTest::TestNumberAsStringParsing()
3901 {
3902     const NumAsStringItem items[] = {
3903         // loc lenient fail?  datePattern                                         dateString
3904         { "",   FALSE, TRUE,  UnicodeString("y MMMM d HH:mm:ss"),                 UnicodeString("2009 7 14 08:43:57") },
3905         { "",   TRUE,  FALSE, UnicodeString("y MMMM d HH:mm:ss"),                 UnicodeString("2009 7 14 08:43:57") },
3906         { "en", FALSE, FALSE, UnicodeString("MMM d, y"),                          UnicodeString("Jul 14, 2009") },
3907         { "en", TRUE,  FALSE, UnicodeString("MMM d, y"),                          UnicodeString("Jul 14, 2009") },
3908         { "en", FALSE, TRUE,  UnicodeString("MMM d, y"),                          UnicodeString("7 14, 2009") },
3909         { "en", TRUE,  FALSE, UnicodeString("MMM d, y"),                          UnicodeString("7 14, 2009") },
3910         { "ja", FALSE, FALSE, UnicodeString("yyyy/MM/dd"),                        UnicodeString("2009/07/14")         },
3911         { "ja", TRUE,  FALSE, UnicodeString("yyyy/MM/dd"),                        UnicodeString("2009/07/14")         },
3912       //{ "ja", FALSE, FALSE, UnicodeString("yyyy/MMMMM/d"),                      UnicodeString("2009/7/14")          }, // #8860 covers test failure
3913         { "ja", TRUE,  FALSE, UnicodeString("yyyy/MMMMM/d"),                      UnicodeString("2009/7/14")          },
3914         { "ja", FALSE, FALSE, CharsToUnicodeString("y\\u5E74M\\u6708d\\u65E5"),   CharsToUnicodeString("2009\\u5E747\\u670814\\u65E5")   },
3915         { "ja", TRUE,  FALSE, CharsToUnicodeString("y\\u5E74M\\u6708d\\u65E5"),   CharsToUnicodeString("2009\\u5E747\\u670814\\u65E5")   },
3916         { "ja", FALSE, FALSE, CharsToUnicodeString("y\\u5E74MMMd\\u65E5"),        CharsToUnicodeString("2009\\u5E747\\u670814\\u65E5")   },
3917         { "ja", TRUE,  FALSE, CharsToUnicodeString("y\\u5E74MMMd\\u65E5"),        CharsToUnicodeString("2009\\u5E747\\u670814\\u65E5")   }, // #8820 fixes test failure
3918         { "ko", FALSE, FALSE, UnicodeString("yyyy. M. d."),                       UnicodeString("2009. 7. 14.")       },
3919         { "ko", TRUE,  FALSE, UnicodeString("yyyy. M. d."),                       UnicodeString("2009. 7. 14.")       },
3920         { "ko", FALSE, FALSE, UnicodeString("yyyy. MMMMM d."),                    CharsToUnicodeString("2009. 7\\uC6D4 14.")             },
3921         { "ko", TRUE,  FALSE, UnicodeString("yyyy. MMMMM d."),                    CharsToUnicodeString("2009. 7\\uC6D4 14.")             }, // #8820 fixes test failure
3922         { "ko", FALSE, FALSE, CharsToUnicodeString("y\\uB144 M\\uC6D4 d\\uC77C"), CharsToUnicodeString("2009\\uB144 7\\uC6D4 14\\uC77C") },
3923         { "ko", TRUE,  FALSE, CharsToUnicodeString("y\\uB144 M\\uC6D4 d\\uC77C"), CharsToUnicodeString("2009\\uB144 7\\uC6D4 14\\uC77C") },
3924         { "ko", FALSE, FALSE, CharsToUnicodeString("y\\uB144 MMM d\\uC77C"),      CharsToUnicodeString("2009\\uB144 7\\uC6D4 14\\uC77C") },
3925         { "ko", TRUE,  FALSE, CharsToUnicodeString("y\\uB144 MMM d\\uC77C"),      CharsToUnicodeString("2009\\uB144 7\\uC6D4 14\\uC77C") }, // #8820 fixes test failure
3926         { NULL, FALSE, FALSE, UnicodeString(""),                                  UnicodeString("")                   }
3927     };
3928     const NumAsStringItem * itemPtr;
3929     for (itemPtr = items; itemPtr->localeStr != NULL; itemPtr++ ) {
3930         Locale locale = Locale::createFromName(itemPtr->localeStr);
3931         UErrorCode status = U_ZERO_ERROR;
3932         SimpleDateFormat formatter(itemPtr->datePattern, locale, status);
3933         if (U_FAILURE(status)) {
3934             dataerrln("Unable to create SimpleDateFormat - %s", u_errorName(status));
3935             return;
3936         }
3937 
3938         formatter.setLenient(itemPtr->lenient);
3939         formatter.setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, itemPtr->lenient, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, itemPtr->lenient, status);
3940         UDate date1 = formatter.parse(itemPtr->dateString, status);
3941         if (U_FAILURE(status)) {
3942             if (!itemPtr->expectFail) {
3943                 errln("FAIL, err when expected success: Locale \"" + UnicodeString(itemPtr->localeStr) + "\", lenient " + itemPtr->lenient +
3944                         ": using pattern \"" + itemPtr->datePattern + "\", could not parse \"" + itemPtr->dateString + "\"; err: " + u_errorName(status) );
3945             }
3946         } else if (itemPtr->expectFail) {
3947                 errln("FAIL, expected err but got none: Locale \"" + UnicodeString(itemPtr->localeStr) + "\", lenient " + itemPtr->lenient +
3948                         ": using pattern \"" + itemPtr->datePattern + "\", did parse \"" + itemPtr->dateString + "\"." );
3949         } else if (!itemPtr->lenient) {
3950             UnicodeString formatted;
3951             formatter.format(date1, formatted);
3952             if (formatted != itemPtr->dateString) {
3953                 errln("FAIL, mismatch formatting parsed date: Locale \"" + UnicodeString(itemPtr->localeStr) + "\", lenient " + itemPtr->lenient +
3954                         ": using pattern \"" + itemPtr->datePattern + "\", did parse \"" + itemPtr->dateString + "\", formatted result \"" + formatted + "\".");
3955             }
3956         }
3957     }
3958 }
3959 
TestISOEra()3960 void DateFormatTest::TestISOEra() {
3961 
3962     const char* data[] = {
3963     // input, output
3964     "BC 4004-10-23T07:00:00Z", "BC 4004-10-23T07:00:00Z",
3965     "AD 4004-10-23T07:00:00Z", "AD 4004-10-23T07:00:00Z",
3966     "-4004-10-23T07:00:00Z"  , "BC 4005-10-23T07:00:00Z",
3967     "4004-10-23T07:00:00Z"   , "AD 4004-10-23T07:00:00Z",
3968     };
3969 
3970     int32_t numData = 8;
3971 
3972     UErrorCode status = U_ZERO_ERROR;
3973 
3974     // create formatter
3975     SimpleDateFormat *fmt1 = new SimpleDateFormat(UnicodeString("GGG yyyy-MM-dd'T'HH:mm:ss'Z"), status);
3976     failure(status, "new SimpleDateFormat", TRUE);
3977     if (status == U_MISSING_RESOURCE_ERROR) {
3978         if (fmt1 != NULL) {
3979             delete fmt1;
3980         }
3981         return;
3982     }
3983     for(int i=0; i < numData; i+=2) {
3984         // create input string
3985         UnicodeString in = data[i];
3986 
3987         // parse string to date
3988         UDate dt1 = fmt1->parse(in, status);
3989         failure(status, "fmt->parse", TRUE);
3990 
3991         // format date back to string
3992         UnicodeString out;
3993         out = fmt1->format(dt1, out);
3994         logln(out);
3995 
3996         // check that roundtrip worked as expected
3997         UnicodeString expected = data[i+1];
3998         if (out != expected) {
3999             dataerrln((UnicodeString)"FAIL: " + in + " -> " + out + " expected -> " + expected);
4000         }
4001     }
4002 
4003     delete fmt1;
4004 }
TestFormalChineseDate()4005 void DateFormatTest::TestFormalChineseDate() {
4006 
4007     UErrorCode status = U_ZERO_ERROR;
4008     UnicodeString pattern(u"y\u5e74M\u6708d\u65e5");
4009     UnicodeString numsys_override(u"y=hanidec;M=hans;d=hans");
4010 
4011     // create formatter
4012     SimpleDateFormat sdf(pattern, numsys_override, Locale::getChina(),status);
4013     if (failure(status, "new SimpleDateFormat with override", true)) {
4014         return;
4015     }
4016 
4017     UDate thedate = date(2009-1900, UCAL_JULY, 28);
4018     FieldPosition pos(FieldPosition::DONT_CARE);
4019     UnicodeString result;
4020     sdf.format(thedate,result,pos);
4021 
4022     UnicodeString expected = "\\u4e8c\\u3007\\u3007\\u4e5d\\u5e74\\u4e03\\u6708\\u4e8c\\u5341\\u516b\\u65e5";
4023     expected = expected.unescape();
4024     if (result != expected) {
4025         dataerrln((UnicodeString)"FAIL: -> " + result + " expected -> " + expected);
4026     }
4027 
4028     UDate parsedate = sdf.parse(expected,status);
4029     if ( parsedate != thedate ) {
4030         UnicodeString pat1 ("yyyy-MM-dd'T'HH:mm:ss'Z'", -1, US_INV );
4031         SimpleDateFormat usf(pat1, Locale::getEnglish(), status);
4032         UnicodeString parsedres,expres;
4033         usf.format(parsedate,parsedres,pos);
4034         usf.format(thedate,expres,pos);
4035         dataerrln((UnicodeString)"FAIL: parsed -> " + parsedres + " expected -> " + expres);
4036     }
4037 }
4038 
4039 // Test case for #8675
4040 // Incorrect parse offset with stand alone GMT string on 2nd or later iteration.
TestStandAloneGMTParse()4041 void DateFormatTest::TestStandAloneGMTParse() {
4042     UErrorCode status = U_ZERO_ERROR;
4043     SimpleDateFormat sdf("ZZZZ", Locale(""), status);
4044 
4045     if (U_SUCCESS(status)) {
4046 
4047         UnicodeString inText(u"GMT$$$");
4048         for (int32_t i = 0; i < 10; i++) {
4049             ParsePosition pos(0);
4050             sdf.parse(inText, pos);
4051             if (pos.getIndex() != 3) {
4052                 errln((UnicodeString)"FAIL: Incorrect output parse position: actual=" + pos.getIndex() + " expected=3");
4053             }
4054         }
4055 
4056     } else {
4057         dataerrln("Unable to create SimpleDateFormat - %s", u_errorName(status));
4058     }
4059 }
4060 
TestParsePosition()4061 void DateFormatTest::TestParsePosition() {
4062     const char* TestData[][4] = {
4063         // {<pattern>, <lead>, <date string>, <trail>}
4064         {"yyyy-MM-dd HH:mm:ssZ", "", "2010-01-10 12:30:00+0500", ""},
4065         {"yyyy-MM-dd HH:mm:ss ZZZZ", "", "2010-01-10 12:30:00 GMT+05:00", ""},
4066         {"Z HH:mm:ss", "", "-0100 13:20:30", ""},
4067         {"y-M-d Z", "", "2011-8-25 -0400", " Foo"},
4068         {"y/M/d H:mm:ss z", "", "2011/7/1 12:34:00 PDT", ""},
4069         {"y/M/d H:mm:ss z", "+123", "2011/7/1 12:34:00 PDT", " PST"},
4070         {"vvvv a h:mm:ss", "", "Pacific Time AM 10:21:45", ""},
4071         {"HH:mm v M/d", "111", "14:15 PT 8/10", " 12345"},
4072         {"'time zone:' VVVV 'date:' yyyy-MM-dd", "xxxx", "time zone: Los Angeles Time date: 2010-02-25", "xxxx"},
4073         {"yG", "", "2012AD", ""},
4074         {"yG", "", "2012", "x"},
4075         {0, 0, 0, 0},
4076     };
4077 
4078     for (int32_t i = 0; TestData[i][0]; i++) {
4079         UErrorCode status = U_ZERO_ERROR;
4080         SimpleDateFormat sdf(UnicodeString(TestData[i][0]), status);
4081         if (failure(status, "new SimpleDateFormat", TRUE)) return;
4082 
4083         int32_t startPos, resPos;
4084 
4085         // lead text
4086         UnicodeString input(TestData[i][1]);
4087         startPos = input.length();
4088 
4089         // date string
4090         input += TestData[i][2];
4091         resPos = input.length();
4092 
4093         // trail text
4094         input += TestData[i][3];
4095 
4096         ParsePosition pos(startPos);
4097         //UDate d = sdf->parse(input, pos);
4098         (void)sdf.parse(input, pos);
4099 
4100         if (pos.getIndex() != resPos) {
4101             errln(UnicodeString("FAIL: Parsing [") + input + "] with pattern [" + TestData[i][0] + "] returns position - "
4102                 + pos.getIndex() + ", expected - " + resPos);
4103         }
4104     }
4105 }
4106 
4107 
4108 typedef struct {
4109     int32_t era;
4110     int32_t year;
4111     int32_t month; // 1-based
4112     int32_t isLeapMonth;
4113     int32_t day;
4114 } ChineseCalTestDate;
4115 
4116 #define NUM_TEST_DATES 3
4117 
4118 typedef struct {
4119     const char *   locale;
4120     int32_t        style; // <0 => custom
4121     UnicodeString  dateString[NUM_TEST_DATES];
4122 } MonthPatternItem;
4123 
TestMonthPatterns()4124 void DateFormatTest::TestMonthPatterns()
4125 {
4126     const ChineseCalTestDate dates[NUM_TEST_DATES] = {
4127         // era yr mo lp da
4128         {  78, 29, 4, 0, 2 }, // (in chinese era 78) gregorian 2012-4-22
4129         {  78, 29, 4, 1, 2 }, // (in chinese era 78) gregorian 2012-5-22
4130         {  78, 29, 5, 0, 2 }, // (in chinese era 78) gregorian 2012-6-20
4131     };
4132 
4133     const MonthPatternItem items[] = {
4134         // locale                     date style;           expected formats for the 3 dates above
4135         { "root@calendar=chinese",    DateFormat::kLong,  { UnicodeString("2012(ren-chen) M04 2"),  UnicodeString("2012(ren-chen) M04bis 2"),  UnicodeString("2012(ren-chen) M05 2") } },
4136         { "root@calendar=chinese",    DateFormat::kShort, { UnicodeString("2012-04-02"),    UnicodeString("2012-04bis-02"),         UnicodeString("2012-05-02") } },
4137         { "root@calendar=chinese",    -1,                 { UnicodeString("29-4-2"),        UnicodeString("29-4bis-2"),             UnicodeString("29-5-2") } },
4138         { "root@calendar=chinese",    -2,                 { UnicodeString("78x29-4-2"),     UnicodeString("78x29-4bis-2"),          UnicodeString("78x29-5-2") } },
4139         { "root@calendar=chinese",    -3,                 { UnicodeString("ren-chen-4-2"),  UnicodeString("ren-chen-4bis-2"),       UnicodeString("ren-chen-5-2") } },
4140         { "root@calendar=chinese",    -4,                 { UnicodeString("ren-chen M04 2"),  UnicodeString("ren-chen M04bis 2"),   UnicodeString("ren-chen M05 2") } },
4141         { "en@calendar=gregorian",    -3,                 { UnicodeString("2012-4-22"),     UnicodeString("2012-5-22"),             UnicodeString("2012-6-20") } },
4142         { "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)") } },
4143         { "en@calendar=chinese",      DateFormat::kShort, { UnicodeString("4/2/2012"),      UnicodeString("4bis/2/2012"),           UnicodeString("5/2/2012") } },
4144         { "zh@calendar=chinese",      DateFormat::kLong,  { CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u56DB\\u6708\\u521D\\u4E8C"),
4145                                                             CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u95F0\\u56DB\\u6708\\u521D\\u4E8C"),
4146                                                             CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u4E94\\u6708\\u521D\\u4E8C") } },
4147         { "zh@calendar=chinese",      DateFormat::kShort, { CharsToUnicodeString("2012/4/2"),
4148                                                             CharsToUnicodeString("2012/\\u95F04/2"),
4149                                                             CharsToUnicodeString("2012/5/2") } },
4150         { "zh@calendar=chinese",      -3,                 { CharsToUnicodeString("\\u58EC\\u8FB0-4-2"),
4151                                                             CharsToUnicodeString("\\u58EC\\u8FB0-\\u95F04-2"),
4152                                                             CharsToUnicodeString("\\u58EC\\u8FB0-5-2") } },
4153         { "zh@calendar=chinese",      -4,                 { CharsToUnicodeString("\\u58EC\\u8FB0 \\u56DB\\u6708 2"),
4154                                                             CharsToUnicodeString("\\u58EC\\u8FB0 \\u95F0\\u56DB\\u6708 2"),
4155                                                             CharsToUnicodeString("\\u58EC\\u8FB0 \\u4E94\\u6708 2") } },
4156         { "zh_Hant@calendar=chinese", DateFormat::kLong,  { CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u56DB\\u6708\\u521D\\u4E8C"),
4157                                                             CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u958F\\u56DB\\u6708\\u521D\\u4E8C"),
4158                                                             CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u4E94\\u6708\\u521D\\u4E8C") } },
4159         { "zh_Hant@calendar=chinese", DateFormat::kShort, { CharsToUnicodeString("2012/4/2"),
4160                                                             CharsToUnicodeString("2012/\\u958F4/2"),
4161                                                             CharsToUnicodeString("2012/5/2") } },
4162         { "fr@calendar=chinese",      DateFormat::kLong,  { CharsToUnicodeString("2 s\\u00ECyu\\u00E8 ren-chen"),
4163                                                             CharsToUnicodeString("2 s\\u00ECyu\\u00E8bis ren-chen"),
4164                                                             CharsToUnicodeString("2 w\\u01D4yu\\u00E8 ren-chen") } },
4165         { "fr@calendar=chinese",      DateFormat::kShort, { UnicodeString("2/4/29"),        UnicodeString("2/4bis/29"),             UnicodeString("2/5/29") } },
4166         { "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)") } },
4167         { "en@calendar=dangi",        DateFormat::kShort, { UnicodeString("3bis/2/2012"),   UnicodeString("4/2/2012"),              UnicodeString("5/1/2012") } },
4168         { "en@calendar=dangi",        -2,                 { UnicodeString("78x29-3bis-2"),  UnicodeString("78x29-4-2"),             UnicodeString("78x29-5-1") } },
4169         { "ko@calendar=dangi",        DateFormat::kLong,  { CharsToUnicodeString("\\uC784\\uC9C4\\uB144 \\uC7243\\uC6D4 2\\uC77C"),
4170                                                             CharsToUnicodeString("\\uC784\\uC9C4\\uB144 4\\uC6D4 2\\uC77C"),
4171                                                             CharsToUnicodeString("\\uC784\\uC9C4\\uB144 5\\uC6D4 1\\uC77C") } },
4172         { "ko@calendar=dangi",        DateFormat::kShort, { CharsToUnicodeString("29. \\uC7243. 2."),
4173                                                             CharsToUnicodeString("29. 4. 2."),
4174                                                             CharsToUnicodeString("29. 5. 1.") } },
4175         // terminator
4176         { NULL,                       0,                  { UnicodeString(""), UnicodeString(""), UnicodeString("") } }
4177     };
4178 
4179     //.                               style: -1        -2            -3       -4
4180     const UnicodeString customPatterns[] = { "y-Ml-d", "G'x'y-Ml-d", "U-M-d", "U MMM d" }; // like old root pattern, using 'l'
4181 
4182     UErrorCode status = U_ZERO_ERROR;
4183     Locale rootChineseCalLocale = Locale::createFromName("root@calendar=chinese");
4184     Calendar * rootChineseCalendar = Calendar::createInstance(rootChineseCalLocale, status);
4185     if (U_SUCCESS(status)) {
4186         const MonthPatternItem * itemPtr;
4187         for (itemPtr = items; itemPtr->locale != NULL; itemPtr++ ) {
4188             Locale locale = Locale::createFromName(itemPtr->locale);
4189             DateFormat * dmft = (itemPtr->style >= 0)?
4190                     DateFormat::createDateInstance((DateFormat::EStyle)itemPtr->style, locale):
4191                     new SimpleDateFormat(customPatterns[-itemPtr->style - 1], locale, status);
4192             if ( dmft != NULL ) {
4193                 if (U_SUCCESS(status)) {
4194                     const ChineseCalTestDate * datePtr = dates;
4195                     int32_t idate;
4196                     for (idate = 0; idate < NUM_TEST_DATES; idate++, datePtr++) {
4197                         rootChineseCalendar->clear();
4198                         rootChineseCalendar->set(UCAL_ERA, datePtr->era);
4199                         rootChineseCalendar->set(datePtr->year, datePtr->month-1, datePtr->day);
4200                         rootChineseCalendar->set(UCAL_IS_LEAP_MONTH, datePtr->isLeapMonth);
4201                         UnicodeString result;
4202                         FieldPosition fpos(FieldPosition::DONT_CARE);
4203                         dmft->format(*rootChineseCalendar, result, fpos);
4204                         if ( result.compare(itemPtr->dateString[idate]) != 0 ) {
4205                             errln( UnicodeString("FAIL: Chinese calendar format for locale ") + UnicodeString(itemPtr->locale) + ", style " + itemPtr->style +
4206                                     ", expected \"" + itemPtr->dateString[idate] + "\", got \"" + result + "\"");
4207                         } else {
4208                             // formatted OK, try parse
4209                             ParsePosition ppos(0);
4210                             // ensure we are really parsing the fields we should be
4211                             rootChineseCalendar->set(UCAL_YEAR, 1);
4212                             rootChineseCalendar->set(UCAL_MONTH, 0);
4213                             rootChineseCalendar->set(UCAL_IS_LEAP_MONTH, 0);
4214                             rootChineseCalendar->set(UCAL_DATE, 1);
4215                             //
4216                             dmft->parse(result, *rootChineseCalendar, ppos);
4217                             int32_t year = rootChineseCalendar->get(UCAL_YEAR, status);
4218                             int32_t month = rootChineseCalendar->get(UCAL_MONTH, status) + 1;
4219                             int32_t isLeapMonth = rootChineseCalendar->get(UCAL_IS_LEAP_MONTH, status);
4220                             int32_t day = rootChineseCalendar->get(UCAL_DATE, status);
4221                             if ( ppos.getIndex() < result.length() || year != datePtr->year || month != datePtr->month || isLeapMonth != datePtr->isLeapMonth || day != datePtr->day ) {
4222                                 errln( UnicodeString("FAIL: Chinese calendar parse for locale ") + UnicodeString(itemPtr->locale) + ", style " + itemPtr->style +
4223                                     ", string \"" + result + "\", expected " + datePtr->year +"-"+datePtr->month+"("+datePtr->isLeapMonth+")-"+datePtr->day + ", got pos " +
4224                                     ppos.getIndex() + " " + year +"-"+month+"("+isLeapMonth+")-"+day);
4225                             }
4226                         }
4227                     }
4228                 } else {
4229                     dataerrln("Error creating SimpleDateFormat for Chinese calendar- %s", u_errorName(status));
4230                 }
4231                 delete dmft;
4232             } else {
4233                 dataerrln("FAIL: Unable to create DateFormat for Chinese calendar- %s", u_errorName(status));
4234             }
4235         }
4236         delete rootChineseCalendar;
4237     } else {
4238         errln(UnicodeString("FAIL: Unable to create Calendar for root@calendar=chinese"));
4239     }
4240 }
4241 
4242 typedef struct {
4243     const char * locale;
4244     UnicodeString pattern;
4245     UDisplayContext capitalizationContext;
4246     UnicodeString expectedFormat;
4247 } TestContextItem;
4248 
TestContext()4249 void DateFormatTest::TestContext()
4250 {
4251     const UDate july022008 = 1215000001979.0;
4252     const TestContextItem items[] = {
4253         //locale              pattern    capitalizationContext                              expected formatted date
4254         { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_NONE,                      UnicodeString("juillet 2008") },
4255 #if !UCONFIG_NO_BREAK_ITERATION
4256         { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,    UnicodeString("juillet 2008") },
4257         { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, UnicodeString("Juillet 2008") },
4258         { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,       UnicodeString("juillet 2008") },
4259         { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_FOR_STANDALONE,            UnicodeString("Juillet 2008") },
4260 #endif
4261         { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_NONE,                      CharsToUnicodeString("\\u010Dervenec 2008") },
4262 #if !UCONFIG_NO_BREAK_ITERATION
4263         { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,    CharsToUnicodeString("\\u010Dervenec 2008") },
4264         { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, CharsToUnicodeString("\\u010Cervenec 2008") },
4265         { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU,       CharsToUnicodeString("\\u010Cervenec 2008") },
4266         { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_FOR_STANDALONE,            CharsToUnicodeString("\\u010Dervenec 2008") },
4267 #endif
4268         // terminator
4269         { NULL, UnicodeString(""),       (UDisplayContext)0, UnicodeString("") }
4270     };
4271     UErrorCode status = U_ZERO_ERROR;
4272     Calendar* cal = Calendar::createInstance(status);
4273     if (U_FAILURE(status)) {
4274         dataerrln(UnicodeString("FAIL: Unable to create Calendar for default timezone and locale."));
4275     } else {
4276         cal->setTime(july022008, status);
4277         const TestContextItem * itemPtr;
4278         for (itemPtr = items; itemPtr->locale != NULL; itemPtr++ ) {
4279            Locale locale = Locale::createFromName(itemPtr->locale);
4280            status = U_ZERO_ERROR;
4281            SimpleDateFormat * sdmft = new SimpleDateFormat(itemPtr->pattern, locale, status);
4282            if (U_FAILURE(status)) {
4283                 dataerrln(UnicodeString("FAIL: Unable to create SimpleDateFormat for specified pattern with locale ") + UnicodeString(itemPtr->locale));
4284            } else {
4285                sdmft->setContext(itemPtr->capitalizationContext, status);
4286                UnicodeString result;
4287                FieldPosition pos(FieldPosition::DONT_CARE);
4288                sdmft->format(*cal, result, pos);
4289                if (result.compare(itemPtr->expectedFormat) != 0) {
4290                    errln(UnicodeString("FAIL: format for locale ") + UnicodeString(itemPtr->locale) +
4291                            ", status " + (int)status +
4292                            ", capitalizationContext " + (int)itemPtr->capitalizationContext +
4293                            ", expected " + itemPtr->expectedFormat + ", got " + result);
4294                }
4295            }
4296            if (sdmft) {
4297                delete sdmft;
4298            }
4299         }
4300     }
4301     if (cal) {
4302         delete cal;
4303     }
4304 }
4305 
4306 // test item for a particular locale + calendar and date format
4307 typedef struct {
4308     int32_t era;
4309     int32_t year;
4310     int32_t month;
4311     int32_t day;
4312     int32_t hour;
4313     int32_t minute;
4314     UnicodeString formattedDate;
4315 } CalAndFmtTestItem;
4316 
4317 // test item giving locale + calendar, date format, and CalAndFmtTestItems
4318 typedef struct {
4319     const char * locale; // with calendar
4320     DateFormat::EStyle style;
4321     UnicodeString pattern; // ignored unless style == DateFormat::kNone
4322     const CalAndFmtTestItem *caftItems;
4323 } TestNonGregoItem;
4324 
TestNonGregoFmtParse()4325 void DateFormatTest::TestNonGregoFmtParse()
4326 {
4327     // test items for he@calendar=hebrew, long date format
4328     const CalAndFmtTestItem cafti_he_hebrew_long[] = {
4329         {  0, 4999, 12, 29, 12, 0, CharsToUnicodeString("\\u05DB\\u05F4\\u05D8 \\u05D1\\u05D0\\u05DC\\u05D5\\u05DC \\u05D3\\u05F3\\u05EA\\u05EA\\u05E7\\u05E6\\u05F4\\u05D8") },
4330         {  0, 5100,  0,  1, 12, 0, CharsToUnicodeString("\\u05D0\\u05F3 \\u05D1\\u05EA\\u05E9\\u05E8\\u05D9 \\u05E7\\u05F3") },
4331         {  0, 5774,  5,  1, 12, 0, CharsToUnicodeString("\\u05D0\\u05F3 \\u05D1\\u05D0\\u05D3\\u05E8 \\u05D0\\u05F3 \\u05EA\\u05E9\\u05E2\\u05F4\\u05D3") },
4332         {  0, 5999, 12, 29, 12, 0, CharsToUnicodeString("\\u05DB\\u05F4\\u05D8 \\u05D1\\u05D0\\u05DC\\u05D5\\u05DC \\u05EA\\u05EA\\u05E7\\u05E6\\u05F4\\u05D8") },
4333         {  0, 6100,  0,  1, 12, 0, CharsToUnicodeString("\\u05D0\\u05F3 \\u05D1\\u05EA\\u05E9\\u05E8\\u05D9 \\u05D5\\u05F3\\u05E7\\u05F3") },
4334         {  0,    0,  0,  0,  0, 0, UnicodeString("") } // terminator
4335     };
4336     const CalAndFmtTestItem cafti_zh_chinese_custU[] = {
4337         { 78,   31,  0,  1, 12, 0, CharsToUnicodeString("2014\\u7532\\u5348\\u5E74\\u6B63\\u67081") },
4338         { 77,   31,  0,  1, 12, 0, CharsToUnicodeString("1954\\u7532\\u5348\\u5E74\\u6B63\\u67081") },
4339         {  0,    0,  0,  0,  0, 0, UnicodeString("") } // terminator
4340     };
4341     const CalAndFmtTestItem cafti_zh_chinese_custNoU[] = {
4342         { 78,   31,  0,  1, 12, 0, CharsToUnicodeString("2014\\u5E74\\u6B63\\u67081") },
4343         { 77,   31,  0,  1, 12, 0, CharsToUnicodeString("1954\\u5E74\\u6B63\\u67081") },
4344         {  0,    0,  0,  0,  0, 0, UnicodeString("") } // terminator
4345     };
4346     const CalAndFmtTestItem cafti_ja_japanese_custGy[] = {
4347         {235,   26,  2,  5, 12, 0, CharsToUnicodeString("2014(\\u5E73\\u621026)\\u5E743\\u67085\\u65E5") },
4348         {234,   60,  2,  5, 12, 0, CharsToUnicodeString("1985(\\u662D\\u548C60)\\u5E743\\u67085\\u65E5") },
4349         {  0,    0,  0,  0,  0, 0, UnicodeString("") } // terminator
4350     };
4351     const CalAndFmtTestItem cafti_ja_japanese_custNoGy[] = {
4352         {235,   26,  2,  5, 12, 0, CharsToUnicodeString("2014\\u5E743\\u67085\\u65E5") },
4353         {234,   60,  2,  5, 12, 0, CharsToUnicodeString("1985\\u5E743\\u67085\\u65E5") },
4354         {  0,    0,  0,  0,  0, 0, UnicodeString("") } // terminator
4355     };
4356     const CalAndFmtTestItem cafti_en_islamic_cust[] = {
4357         {  0, 1384,  0,  1, 12, 0, UnicodeString("1 Muh. 1384 AH, 1964") },
4358         {  0, 1436,  0,  1, 12, 0, UnicodeString("1 Muh. 1436 AH, 2014") },
4359         {  0, 1487,  0,  1, 12, 0, UnicodeString("1 Muh. 1487 AH, 2064") },
4360         {  0,    0,  0,  0,  0, 0, UnicodeString("") } // terminator
4361     };
4362     // overal test items
4363     const TestNonGregoItem items[] = {
4364         { "he@calendar=hebrew",   DateFormat::kLong, UnicodeString(""),                 cafti_he_hebrew_long },
4365         { "zh@calendar=chinese",  DateFormat::kNone, CharsToUnicodeString("rU\\u5E74MMMd"),                cafti_zh_chinese_custU },
4366         { "zh@calendar=chinese",  DateFormat::kNone, CharsToUnicodeString("r\\u5E74MMMd"),                 cafti_zh_chinese_custNoU },
4367         { "ja@calendar=japanese", DateFormat::kNone, CharsToUnicodeString("r(Gy)\\u5E74M\\u6708d\\u65E5"), cafti_ja_japanese_custGy },
4368         { "ja@calendar=japanese", DateFormat::kNone, CharsToUnicodeString("r\\u5E74M\\u6708d\\u65E5"),     cafti_ja_japanese_custNoGy },
4369         { "en@calendar=islamic",  DateFormat::kNone, UnicodeString("d MMM y G, r"),     cafti_en_islamic_cust },
4370         { NULL, DateFormat::kNone, UnicodeString(""), NULL } // terminator
4371     };
4372     const TestNonGregoItem * itemPtr;
4373     for (itemPtr = items; itemPtr->locale != NULL; itemPtr++) {
4374         Locale locale = Locale::createFromName(itemPtr->locale);
4375         LocalPointer<DateFormat> dfmt;
4376         UErrorCode status = U_ZERO_ERROR;
4377         if (itemPtr->style != DateFormat::kNone) {
4378             dfmt.adoptInstead(DateFormat::createDateInstance(itemPtr->style, locale));
4379         } else {
4380             dfmt.adoptInstead(new SimpleDateFormat(itemPtr->pattern, locale, status));
4381         }
4382         if (U_FAILURE(status)) {
4383             dataerrln("new SimpleDateFormat fails for locale %s", itemPtr->locale);
4384         } else  if (!dfmt.isValid()) {
4385             dataerrln("DateFormat::createDateInstance fails for locale %s", itemPtr->locale);
4386         } else {
4387             LocalPointer<Calendar>cal((dfmt->getCalendar())->clone());
4388             if (!cal.isValid()) {
4389                 dataerrln("(DateFormat::getCalendar)->clone() fails for locale %s", itemPtr->locale);
4390             } else {
4391                 const CalAndFmtTestItem * caftItemPtr;
4392                 for (caftItemPtr = itemPtr->caftItems; caftItemPtr->year != 0; caftItemPtr++) {
4393                     cal->clear();
4394                     cal->set(UCAL_ERA,    caftItemPtr->era);
4395                     cal->set(UCAL_YEAR,   caftItemPtr->year);
4396                     cal->set(UCAL_MONTH,  caftItemPtr->month);
4397                     cal->set(UCAL_DATE,   caftItemPtr->day);
4398                     cal->set(UCAL_HOUR_OF_DAY, caftItemPtr->hour);
4399                     cal->set(UCAL_MINUTE, caftItemPtr->minute);
4400                     UnicodeString result;
4401                     FieldPosition fpos(FieldPosition::DONT_CARE);
4402                     dfmt->format(*cal, result, fpos);
4403                     if ( result.compare(caftItemPtr->formattedDate) != 0 ) {
4404                         errln( UnicodeString("FAIL: date format for locale ") + UnicodeString(itemPtr->locale) + ", style " + itemPtr->style +
4405                                 ", expected \"" + caftItemPtr->formattedDate + "\", got \"" + result + "\"");
4406                     } else {
4407                         // formatted OK, try parse
4408                         ParsePosition ppos(0);
4409                         dfmt->parse(result, *cal, ppos);
4410                         status = U_ZERO_ERROR;
4411                         int32_t era = cal->get(UCAL_ERA, status);
4412                         int32_t year = cal->get(UCAL_YEAR, status);
4413                         int32_t month = cal->get(UCAL_MONTH, status);
4414                         int32_t day = cal->get(UCAL_DATE, status);
4415                         if ( U_FAILURE(status) || ppos.getIndex() < result.length() || era != caftItemPtr->era ||
4416                                 year != caftItemPtr->year || month != caftItemPtr->month || day != caftItemPtr->day ) {
4417                             errln( UnicodeString("FAIL: date parse for locale ") + UnicodeString(itemPtr->locale) +
4418                                 ", style " + itemPtr->style + ", string \"" + result + "\", expected " +
4419                                 caftItemPtr->era +":"+caftItemPtr->year +"-"+caftItemPtr->month+"-"+caftItemPtr->day + ", got pos " +
4420                                 ppos.getIndex() + " " + year +"-"+month+"-"+day + " status " + UnicodeString(u_errorName(status)) );
4421                         }
4422                     }
4423                 }
4424             }
4425         }
4426     }
4427 }
4428 
4429 typedef struct {
4430     const char*         localeID;
4431     DateFormat::EStyle  style;
4432     UnicodeString       expectPattern;
4433     UnicodeString       expectFormat;
4434 } TestFmtWithNumSysItem;
4435 enum { kBBufMax = 128 };
TestFormatsWithNumberSystems()4436 void DateFormatTest::TestFormatsWithNumberSystems()
4437 {
4438     LocalPointer<TimeZone> zone(TimeZone::createTimeZone(UnicodeString("UTC")));
4439     const UDate date = 1451556000000.0; // for UTC: grego 31-Dec-2015 10 AM, hebrew 19 tevet 5776, chinese yi-wei 11mo 21day
4440     const TestFmtWithNumSysItem items[] = {
4441         { "haw@calendar=gregorian", DateFormat::kShort, UnicodeString("d/M/yy"),               UnicodeString("31/xii/15") },
4442         { "he@calendar=hebrew",     DateFormat::kLong, CharsToUnicodeString("d \\u05D1MMMM y"), CharsToUnicodeString("\\u05D9\\u05F4\\u05D8 \\u05D1\\u05D8\\u05D1\\u05EA \\u05EA\\u05E9\\u05E2\\u05F4\\u05D5") },
4443         { "zh@calendar=chinese",      DateFormat::kLong, CharsToUnicodeString("rU\\u5E74MMMd"), CharsToUnicodeString("2015\\u4E59\\u672A\\u5E74\\u5341\\u4E00\\u6708\\u5EFF\\u4E00") },
4444         { "zh_Hant@calendar=chinese", DateFormat::kLong, CharsToUnicodeString("rU\\u5E74MMMd"), CharsToUnicodeString("2015\\u4E59\\u672A\\u5E74\\u51AC\\u6708\\u5EFF\\u4E00") },
4445         { "ja@calendar=chinese", DateFormat::kLong, CharsToUnicodeString("U\\u5E74MMMd\\u65E5"), CharsToUnicodeString("\\u4E59\\u672A\\u5E74\\u5341\\u4E00\\u6708\\u4E8C\\u4E00\\u65E5") },
4446         { NULL, DateFormat::kNone, UnicodeString(""), UnicodeString("") },
4447     };
4448     const TestFmtWithNumSysItem * itemPtr;
4449     for (itemPtr = items; itemPtr->localeID != NULL; itemPtr++) {
4450         char bExpected[kBBufMax];
4451         char bResult[kBBufMax];
4452         UErrorCode status = U_ZERO_ERROR;
4453         Locale locale = Locale::createFromName(itemPtr->localeID);
4454         LocalPointer<Calendar> cal(Calendar::createInstance(zone.orphan(), locale, status));
4455         if (U_FAILURE(status)) {
4456             dataerrln("Calendar::createInstance fails for locale %s, status %s", itemPtr->localeID, u_errorName(status));
4457             continue;
4458         }
4459         cal->setTime(date, status);
4460         if (U_FAILURE(status)) {
4461             dataerrln("Calendar::setTime fails for locale %s, date %.1f, status %s", itemPtr->localeID, date, u_errorName(status));
4462             continue;
4463         }
4464         LocalPointer<SimpleDateFormat> sdfmt(static_cast<SimpleDateFormat *>(DateFormat::createDateInstance(itemPtr->style, locale)));
4465         if (sdfmt.isNull()) {
4466             dataerrln("DateFormat::createDateInstance fails for locale %s", itemPtr->localeID);
4467             continue;
4468         }
4469         UnicodeString getFormat;
4470         sdfmt->format(*(cal.getAlias()), getFormat, NULL, status);
4471         if (U_FAILURE(status)) {
4472             errln("DateFormat::format fails for locale %s, status %s", itemPtr->localeID, u_errorName(status));
4473             continue;
4474         }
4475         if (getFormat.compare(itemPtr->expectFormat) != 0) {
4476             itemPtr->expectFormat.extract(0, itemPtr->expectFormat.length(), bExpected, kBBufMax);
4477             getFormat.extract(0, getFormat.length(), bResult, kBBufMax);
4478             errln("DateFormat::format for locale %s, expected \"%s\", got \"%s\"", itemPtr->localeID, bExpected, bResult);
4479         }
4480         UnicodeString getPattern;
4481         sdfmt->toPattern(getPattern);
4482         if (getPattern.compare(itemPtr->expectPattern) != 0) {
4483             itemPtr->expectPattern.extract(0, itemPtr->expectPattern.length(), bExpected, kBBufMax);
4484             getPattern.extract(0, getPattern.length(), bResult, kBBufMax);
4485             errln("DateFormat::toPattern() for locale %s, expected \"%s\", got \"%s\"", itemPtr->localeID, bExpected, bResult);
4486         }
4487     }
4488 }
4489 
4490 static const UDate TEST_DATE = 1326585600000.;  // 2012-jan-15
4491 
TestDotAndAtLeniency()4492 void DateFormatTest::TestDotAndAtLeniency() {
4493     // Test for date/time parsing regression with CLDR 22.1/ICU 50 pattern strings.
4494     // For details see http://bugs.icu-project.org/trac/ticket/9789
4495     static const char *locales[] = { "en", "fr" };
4496     for (int32_t i = 0; i < UPRV_LENGTHOF(locales); ++i) {
4497         Locale locale(locales[i]);
4498 
4499         for (DateFormat::EStyle dateStyle = DateFormat::FULL; dateStyle <= DateFormat::SHORT;
4500                   dateStyle = static_cast<DateFormat::EStyle>(dateStyle + 1)) {
4501             LocalPointer<DateFormat> dateFormat(DateFormat::createDateInstance(dateStyle, locale));
4502 
4503             for (DateFormat::EStyle timeStyle = DateFormat::FULL; timeStyle <= DateFormat::SHORT;
4504                       timeStyle = static_cast<DateFormat::EStyle>(timeStyle + 1)) {
4505                 LocalPointer<DateFormat> format(DateFormat::createDateTimeInstance(dateStyle, timeStyle, locale));
4506                 LocalPointer<DateFormat> timeFormat(DateFormat::createTimeInstance(timeStyle, locale));
4507                 UnicodeString formattedString;
4508                 if (format.isNull()) {
4509                     dataerrln("Unable to create DateFormat");
4510                     continue;
4511                 }
4512                 format->format(TEST_DATE, formattedString);
4513 
4514                 if (!showParse(*format, formattedString)) {
4515                     errln(UnicodeString("    with date-time: dateStyle=") + dateStyle + " timeStyle=" + timeStyle);
4516                 }
4517 
4518                 UnicodeString ds, ts;
4519                 formattedString = dateFormat->format(TEST_DATE, ds) + "  " + timeFormat->format(TEST_DATE, ts);
4520                 if (!showParse(*format, formattedString)) {
4521                     errln(UnicodeString("    with date sp sp time: dateStyle=") + dateStyle + " timeStyle=" + timeStyle);
4522                 }
4523                 if (formattedString.indexOf("n ") >= 0) { // will add "." after the end of text ending in 'n', like Jan.
4524                     UnicodeString plusDot(formattedString);
4525                     plusDot.findAndReplace("n ", "n. ").append(".");
4526                     if (!showParse(*format, plusDot)) {
4527                         errln(UnicodeString("    with date plus-dot time: dateStyle=") + dateStyle + " timeStyle=" + timeStyle);
4528                     }
4529                 }
4530                 if (formattedString.indexOf(". ") >= 0) { // will subtract "." at the end of strings.
4531                     UnicodeString minusDot(formattedString);
4532                     minusDot.findAndReplace(". ", " ");
4533                     if (!showParse(*format, minusDot)) {
4534                         errln(UnicodeString("    with date minus-dot time: dateStyle=") + dateStyle + " timeStyle=" + timeStyle);
4535                     }
4536                 }
4537             }
4538         }
4539     }
4540 }
4541 
showParse(DateFormat & format,const UnicodeString & formattedString)4542 UBool DateFormatTest::showParse(DateFormat &format, const UnicodeString &formattedString) {
4543     ParsePosition parsePosition;
4544     UDate parsed = format.parse(formattedString, parsePosition);
4545     UBool ok = TEST_DATE == parsed && parsePosition.getIndex() == formattedString.length();
4546     UnicodeString pattern;
4547     static_cast<SimpleDateFormat &>(format).toPattern(pattern);
4548     if (ok) {
4549         logln(pattern + "  parsed: " + formattedString);
4550     } else {
4551         errln(pattern + "  fails to parse: " + formattedString);
4552     }
4553     return ok;
4554 }
4555 
4556 
4557 typedef struct {
4558     const char * locale;
4559     UBool leniency;
4560     UnicodeString parseString;
4561     UnicodeString pattern;
4562     UnicodeString expectedResult;       // empty string indicates expected error
4563 } TestDateFormatLeniencyItem;
4564 
TestDateFormatLeniency()4565 void DateFormatTest::TestDateFormatLeniency() {
4566     // For details see http://bugs.icu-project.org/trac/ticket/10261
4567 
4568     const UDate july022008 = 1215000001979.0;
4569     const TestDateFormatLeniencyItem items[] = {
4570         //locale    leniency    parse String                    pattern                             expected result
4571         { "en",     true,       UnicodeString("2008-07 02"),    UnicodeString("yyyy-LLLL dd"),      UnicodeString("2008-July 02") },
4572         { "en",     false,      UnicodeString("2008-07 02"),    UnicodeString("yyyy-LLLL dd"),      UnicodeString("") },
4573         { "en",     true,       UnicodeString("2008-Jan 02"),   UnicodeString("yyyy-LLL. dd"),      UnicodeString("2008-Jan. 02") },
4574         { "en",     false,      UnicodeString("2008-Jan 02"),   UnicodeString("yyyy-LLL. dd"),      UnicodeString("") },
4575         { "en",     true,       UnicodeString("2008-Jan--02"),  UnicodeString("yyyy-MMM' -- 'dd"),  UnicodeString("2008-Jan -- 02") },
4576         { "en",     false,      UnicodeString("2008-Jan--02"),  UnicodeString("yyyy-MMM' -- 'dd"),  UnicodeString("") },
4577         // terminator
4578         { NULL,     true,       UnicodeString(""),              UnicodeString(""),                  UnicodeString("") }
4579     };
4580     UErrorCode status = U_ZERO_ERROR;
4581     LocalPointer<Calendar> cal(Calendar::createInstance(status));
4582     if (U_FAILURE(status)) {
4583         dataerrln(UnicodeString("FAIL: Unable to create Calendar for default timezone and locale."));
4584         return;
4585     }
4586     cal->setTime(july022008, status);
4587     const TestDateFormatLeniencyItem * itemPtr;
4588     LocalPointer<SimpleDateFormat> sdmft;
4589     for (itemPtr = items; itemPtr->locale != NULL; itemPtr++ ) {
4590 
4591        Locale locale = Locale::createFromName(itemPtr->locale);
4592        status = U_ZERO_ERROR;
4593        ParsePosition pos(0);
4594        sdmft.adoptInsteadAndCheckErrorCode(new SimpleDateFormat(itemPtr->pattern, locale, status), status);
4595        if (U_FAILURE(status)) {
4596            dataerrln("Unable to create SimpleDateFormat - %s", u_errorName(status));
4597            continue;
4598        }
4599        sdmft->setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, itemPtr->leniency, status).
4600               setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, itemPtr->leniency, status).
4601               setBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, itemPtr->leniency, status);
4602        UDate d = sdmft->parse(itemPtr->parseString, pos);
4603 
4604        if(itemPtr->expectedResult.length() == 0) {
4605            if(pos.getErrorIndex() != -1) {
4606                continue;
4607            } else {
4608                 errln("error: unexpected parse success - " + itemPtr->parseString +
4609                     " - pattern " + itemPtr->pattern +
4610                     " - error index " + pos.getErrorIndex() +
4611                     " - leniency " + itemPtr->leniency);
4612                 continue;
4613            }
4614        }
4615        if(pos.getErrorIndex() != -1) {
4616            errln("error: parse error for string - "  + itemPtr->parseString +
4617                  " - pattern " + itemPtr->pattern +
4618                  " - idx " + pos.getIndex() +
4619                  " - error index "+pos.getErrorIndex() +
4620                  " - leniency " + itemPtr->leniency);
4621             continue;
4622         }
4623 
4624        UnicodeString formatResult("");
4625        sdmft->format(d, formatResult);
4626        if(formatResult.compare(itemPtr->expectedResult) != 0) {
4627            errln("error: unexpected format result. pattern["+itemPtr->pattern+"] expected[" + itemPtr->expectedResult + "]  but result was[" + formatResult + "]");
4628            continue;
4629         } else {
4630             logln("formatted results match! - " + formatResult);
4631         }
4632 
4633     }
4634 }
4635 
4636 
4637 typedef struct {
4638     UBool leniency;
4639     UnicodeString parseString;
4640     UnicodeString pattern;
4641     UnicodeString expectedResult;       // empty string indicates expected error
4642 } TestMultiPatternMatchItem;
4643 
TestParseMultiPatternMatch()4644 void DateFormatTest::TestParseMultiPatternMatch() {
4645         // For details see http://bugs.icu-project.org/trac/ticket/10336
4646     const TestMultiPatternMatchItem items[] = {
4647           // leniency    parse String                                 pattern                               expected result
4648             {true,       UnicodeString("2013-Sep 13"),                UnicodeString("yyyy-MMM dd"),         UnicodeString("2013-Sep 13")},
4649             {true,       UnicodeString("2013-September 14"),          UnicodeString("yyyy-MMM dd"),         UnicodeString("2013-Sep 14")},
4650             {false,      UnicodeString("2013-September 15"),          UnicodeString("yyyy-MMM dd"),         UnicodeString("")},
4651             {false,      UnicodeString("2013-September 16"),          UnicodeString("yyyy-MMMM dd"),        UnicodeString("2013-September 16")},
4652             {true,       UnicodeString("2013-Sep 17"),                UnicodeString("yyyy-LLL dd"),         UnicodeString("2013-Sep 17")},
4653             {true,       UnicodeString("2013-September 18"),          UnicodeString("yyyy-LLL dd"),         UnicodeString("2013-Sep 18")},
4654             {false,      UnicodeString("2013-September 19"),          UnicodeString("yyyy-LLL dd"),         UnicodeString("")},
4655             {false,      UnicodeString("2013-September 20"),          UnicodeString("yyyy-LLLL dd"),        UnicodeString("2013-September 20")},
4656             {true,       UnicodeString("2013 Sat Sep 21"),            UnicodeString("yyyy EEE MMM dd"),     UnicodeString("2013 Sat Sep 21")},
4657             {true,       UnicodeString("2013 Sunday Sep 22"),         UnicodeString("yyyy EEE MMM dd"),     UnicodeString("2013 Sun Sep 22")},
4658             {false,      UnicodeString("2013 Monday Sep 23"),         UnicodeString("yyyy EEE MMM dd"),     UnicodeString("")},
4659             {false,      UnicodeString("2013 Tuesday Sep 24"),        UnicodeString("yyyy EEEE MMM dd"),    UnicodeString("2013 Tuesday Sep 24")},
4660             {true,       UnicodeString("2013 Wed Sep 25"),            UnicodeString("yyyy eee MMM dd"),     UnicodeString("2013 Wed Sep 25")},
4661             {true,       UnicodeString("2013 Thu Sep 26"),            UnicodeString("yyyy eee MMM dd"),     UnicodeString("2013 Thu Sep 26")},
4662             {false,      UnicodeString("2013 Friday Sep 27"),         UnicodeString("yyyy eee MMM dd"),     UnicodeString("")},
4663             {false,      UnicodeString("2013 Saturday Sep 28"),       UnicodeString("yyyy eeee MMM dd"),    UnicodeString("2013 Saturday Sep 28")},
4664             {true,       UnicodeString("2013 Sun Sep 29"),            UnicodeString("yyyy ccc MMM dd"),     UnicodeString("2013 Sun Sep 29")},
4665             {true,       UnicodeString("2013 Monday Sep 30"),         UnicodeString("yyyy ccc MMM dd"),     UnicodeString("2013 Mon Sep 30")},
4666             {false,      UnicodeString("2013 Sunday Oct 13"),         UnicodeString("yyyy ccc MMM dd"),     UnicodeString("")},
4667             {false,      UnicodeString("2013 Monday Oct 14"),         UnicodeString("yyyy cccc MMM dd"),    UnicodeString("2013 Monday Oct 14")},
4668             {true,       UnicodeString("2013 Oct 15 Q4"),             UnicodeString("yyyy MMM dd QQQ"),     UnicodeString("2013 Oct 15 Q4")},
4669             {true,       UnicodeString("2013 Oct 16 4th quarter"),    UnicodeString("yyyy MMM dd QQQ"),     UnicodeString("2013 Oct 16 Q4")},
4670             {false,      UnicodeString("2013 Oct 17 4th quarter"),    UnicodeString("yyyy MMM dd QQQ"),     UnicodeString("")},
4671             {false,      UnicodeString("2013 Oct 18 Q4"),             UnicodeString("yyyy MMM dd QQQ"),     UnicodeString("2013 Oct 18 Q4")},
4672             {true,       UnicodeString("2013 Oct 19 Q4"),             UnicodeString("yyyy MMM dd qqqq"),    UnicodeString("2013 Oct 19 4th quarter")},
4673             {true,       UnicodeString("2013 Oct 20 4th quarter"),    UnicodeString("yyyy MMM dd qqqq"),    UnicodeString("2013 Oct 20 4th quarter")},
4674             {false,      UnicodeString("2013 Oct 21 Q4"),             UnicodeString("yyyy MMM dd qqqq"),    UnicodeString("")},
4675             {false,      UnicodeString("2013 Oct 22 4th quarter"),    UnicodeString("yyyy MMM dd qqqq"),    UnicodeString("2013 Oct 22 4th quarter")},
4676             {false,      UnicodeString("--end--"),                    UnicodeString(""),                    UnicodeString("")},
4677     };
4678 
4679     UErrorCode status = U_ZERO_ERROR;
4680     LocalPointer<Calendar> cal(Calendar::createInstance(status));
4681     if (U_FAILURE(status)) {
4682         dataerrln(UnicodeString("FAIL: Unable to create Calendar for default timezone and locale."));
4683         return;
4684     }
4685     const TestMultiPatternMatchItem * itemPtr;
4686     DateFormat* sdmft = DateFormat::createDateInstance();
4687     if (sdmft == NULL) {
4688         dataerrln(UnicodeString("FAIL: Unable to create DateFormat"));
4689         return;
4690     }
4691     for (itemPtr = items; itemPtr->parseString != "--end--"; itemPtr++ ) {
4692        status = U_ZERO_ERROR;
4693        ParsePosition pos(0);
4694        ((SimpleDateFormat*) sdmft)->applyPattern(itemPtr->pattern);
4695        if (U_FAILURE(status)) {
4696            dataerrln("Unable to create SimpleDateFormat - %s", u_errorName(status));
4697            continue;
4698        }
4699        sdmft->setBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, itemPtr->leniency, status);
4700        UDate d = sdmft->parse(itemPtr->parseString, pos);
4701 
4702        if(itemPtr->expectedResult.length() == 0) {
4703            if(pos.getErrorIndex() != -1) {
4704                continue;
4705            } else {
4706                 errln("error: unexpected parse success - " + itemPtr->parseString +
4707                     " - error index " + pos.getErrorIndex() +
4708                     " - leniency " + itemPtr->leniency);
4709                 continue;
4710            }
4711         }
4712         if(pos.getErrorIndex() != -1) {
4713             errln("error: parse error for string - " +itemPtr->parseString + " -- idx["+pos.getIndex()+"] errIdx["+pos.getErrorIndex()+"]");
4714             continue;
4715         }
4716 
4717         UnicodeString formatResult("");
4718         sdmft->format(d, formatResult);
4719         if(formatResult.compare(itemPtr->expectedResult) != 0) {
4720             errln("error: unexpected format result. expected[" + itemPtr->expectedResult + "]  but result was[" + formatResult + "]");
4721         } else {
4722             logln("formatted results match! - " + formatResult);
4723         }
4724     }
4725     delete sdmft;
4726 }
4727 
TestParseLeniencyAPIs()4728 void DateFormatTest::TestParseLeniencyAPIs() {
4729     UErrorCode status = U_ZERO_ERROR;
4730     LocalPointer<DateFormat> dateFormat(DateFormat::createDateInstance());
4731     DateFormat *fmt = dateFormat.getAlias();
4732     if (fmt == NULL) {
4733         dataerrln("Failed calling dateFormat.getAlias()");
4734         return;
4735     }
4736 
4737     assertTrue("isLenient default", fmt->isLenient());
4738     assertTrue("isCalendarLenient default", fmt->isCalendarLenient());
4739     assertTrue("ALLOW_WHITESPACE default", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status));
4740     assertTrue("ALLOW_NUMERIC default", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status));
4741     assertTrue("PARTIAL_MATCH default", fmt->getBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, status));
4742     assertTrue("MULTIPLE_PATTERNS default", fmt->getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status));
4743 
4744     // Set calendar to strict
4745     fmt->setCalendarLenient(FALSE);
4746 
4747     assertFalse("isLeninent after setCalendarLenient(FALSE)", fmt->isLenient());
4748     assertFalse("isCalendarLenient after setCalendarLenient(FALSE)", fmt->isCalendarLenient());
4749     assertTrue("ALLOW_WHITESPACE after setCalendarLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status));
4750     assertTrue("ALLOW_NUMERIC  after setCalendarLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status));
4751 
4752     // Set to strict
4753     fmt->setLenient(FALSE);
4754 
4755     assertFalse("isLeninent after setLenient(FALSE)", fmt->isLenient());
4756     assertFalse("isCalendarLenient after setLenient(FALSE)", fmt->isCalendarLenient());
4757     assertFalse("ALLOW_WHITESPACE after setLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status));
4758     assertFalse("ALLOW_NUMERIC  after setLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status));
4759     // These two boolean attributes are NOT affected according to the API specification
4760     assertTrue("PARTIAL_MATCH after setLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, status));
4761     assertTrue("MULTIPLE_PATTERNS after setLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status));
4762 
4763     // Allow white space leniency
4764     fmt->setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, TRUE, status);
4765 
4766     assertFalse("isLeninent after ALLOW_WHITESPACE/TRUE", fmt->isLenient());
4767     assertFalse("isCalendarLenient after ALLOW_WHITESPACE/TRUE", fmt->isCalendarLenient());
4768     assertTrue("ALLOW_WHITESPACE after ALLOW_WHITESPACE/TRUE", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status));
4769     assertFalse("ALLOW_NUMERIC  after ALLOW_WHITESPACE/TRUE", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status));
4770 
4771     // Set to lenient
4772     fmt->setLenient(TRUE);
4773 
4774     assertTrue("isLenient after setLenient(TRUE)", fmt->isLenient());
4775     assertTrue("isCalendarLenient after setLenient(TRUE)", fmt->isCalendarLenient());
4776     assertTrue("ALLOW_WHITESPACE after setLenient(TRUE)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status));
4777     assertTrue("ALLOW_NUMERIC after setLenient(TRUE)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status));
4778 }
4779 
TestNumberFormatOverride()4780 void DateFormatTest::TestNumberFormatOverride() {
4781     UErrorCode status = U_ZERO_ERROR;
4782     UnicodeString fields = (UnicodeString) "M";
4783 
4784     LocalPointer<SimpleDateFormat> fmt;
4785     fmt.adoptInsteadAndCheckErrorCode(new SimpleDateFormat((UnicodeString)"MM d", status), status);
4786     if (!assertSuccess("SimpleDateFormat with pattern MM d", status)) {
4787         return;
4788     }
4789 
4790 
4791     for(int i=0; i<3; i++){
4792         NumberFormat* check_nf = NumberFormat::createInstance(Locale("en_US"), status);
4793         assertSuccess("NumberFormat en_US", status);
4794         fmt->adoptNumberFormat(fields, check_nf, status);
4795         assertSuccess("adoptNumberFormat check_nf", status);
4796 
4797         const NumberFormat* get_nf = fmt->getNumberFormatForField((UChar)0x004D /*'M'*/);
4798         if (get_nf != check_nf) errln("FAIL: getter and setter do not work");
4799     }
4800     NumberFormat* check_nf = NumberFormat::createInstance(Locale("en_US"), status);
4801     assertSuccess("NumberFormat en_US", status);
4802     fmt->adoptNumberFormat(check_nf); // make sure using the same NF will not crash
4803 
4804     const char * DATA [][2] = {
4805         { "", "\\u521D\\u516D \\u5341\\u4E94"},
4806         { "M", "\\u521D\\u516D 15"},
4807         { "Mo", "\\u521D\\u516D 15"},
4808         { "Md", "\\u521D\\u516D \\u5341\\u4E94"},
4809         { "MdMMd", "\\u521D\\u516D \\u5341\\u4E94"},
4810         { "mixed", "\\u521D\\u516D \\u5341\\u4E94"}
4811     };
4812 
4813     UDate test_date = date(97, 6 - 1, 15);
4814 
4815     for(int i=0; i < UPRV_LENGTHOF(DATA); i++){
4816         fields = DATA[i][0];
4817 
4818         LocalPointer<SimpleDateFormat> fmt;
4819         fmt.adoptInsteadAndCheckErrorCode(new SimpleDateFormat((UnicodeString)"MM d", status), status);
4820         assertSuccess("SimpleDateFormat with pattern MM d", status);
4821         NumberFormat* overrideNF = NumberFormat::createInstance(Locale::createFromName("zh@numbers=hanidays"),status);
4822         assertSuccess("NumberFormat zh@numbers=hanidays", status);
4823         if (U_FAILURE(status)) {
4824             status = U_ZERO_ERROR;
4825             continue;
4826         }
4827 
4828         if (fields == (UnicodeString) "") { // use the one w/o fields
4829             fmt->adoptNumberFormat(overrideNF);
4830         } else if (fields == (UnicodeString) "mixed") { // set 1 field at first but then full override, both(M & d) should be override
4831             NumberFormat* singleOverrideNF = NumberFormat::createInstance(Locale::createFromName("en@numbers=hebr"),status);
4832             assertSuccess("NumberFormat en@numbers=hebr", status);
4833 
4834             fields = (UnicodeString) "M";
4835             fmt->adoptNumberFormat(fields, singleOverrideNF, status);
4836             assertSuccess("adoptNumberFormat singleOverrideNF", status);
4837 
4838             fmt->adoptNumberFormat(overrideNF);
4839         } else if (fields == (UnicodeString) "Mo"){ // o is invlid field
4840             fmt->adoptNumberFormat(fields, overrideNF, status);
4841             if(status == U_INVALID_FORMAT_ERROR) {
4842                 status = U_ZERO_ERROR;
4843                 continue;
4844             }
4845         } else {
4846             fmt->adoptNumberFormat(fields, overrideNF, status);
4847             assertSuccess("adoptNumberFormat overrideNF", status);
4848         }
4849 
4850         UnicodeString result;
4851         FieldPosition pos(FieldPosition::DONT_CARE);
4852         fmt->format(test_date,result, pos);
4853 
4854         UnicodeString expected = ((UnicodeString)DATA[i][1]).unescape();
4855 
4856         if (result != expected)
4857             errln("FAIL: Expected " + expected + " get: " + result);
4858     }
4859 }
4860 
TestCreateInstanceForSkeleton()4861 void DateFormatTest::TestCreateInstanceForSkeleton() {
4862     UErrorCode status = U_ZERO_ERROR;
4863     LocalPointer<DateFormat> fmt(DateFormat::createInstanceForSkeleton(
4864             "yMMMMd", "en", status));
4865     if (!assertSuccess("Create with pattern yMMMMd", status)) {
4866         return;
4867     }
4868     UnicodeString result;
4869     FieldPosition pos(FieldPosition::DONT_CARE);
4870     fmt->format(date(98, 5-1, 25), result, pos);
4871     assertEquals("format yMMMMd", "May 25, 1998", result);
4872     fmt.adoptInstead(DateFormat::createInstanceForSkeleton(
4873             "yMd", "en", status));
4874     if (!assertSuccess("Create with pattern yMd", status)) {
4875         return;
4876     }
4877     result.remove();
4878     fmt->format(date(98, 5-1, 25), result, pos);
4879     assertEquals("format yMd", "5/25/1998", result);
4880 }
4881 
TestCreateInstanceForSkeletonDefault()4882 void DateFormatTest::TestCreateInstanceForSkeletonDefault() {
4883     UErrorCode status = U_ZERO_ERROR;
4884     Locale savedLocale;
4885     Locale::setDefault(Locale::getUS(), status);
4886     LocalPointer<DateFormat> fmt(DateFormat::createInstanceForSkeleton(
4887             "yMMMd", status));
4888     Locale::setDefault(savedLocale, status);
4889     if (!assertSuccess("Create with pattern yMMMd", status)) {
4890         return;
4891     }
4892     UnicodeString result;
4893     FieldPosition pos(FieldPosition::DONT_CARE);
4894     fmt->format(date(98, 5-1, 25), result, pos);
4895     assertEquals("format yMMMd", "May 25, 1998", result);
4896 }
4897 
TestCreateInstanceForSkeletonWithCalendar()4898 void DateFormatTest::TestCreateInstanceForSkeletonWithCalendar() {
4899     UErrorCode status = U_ZERO_ERROR;
4900     LocalPointer<DateFormat> fmt(
4901             DateFormat::createInstanceForSkeleton(
4902                     Calendar::createInstance(
4903                             TimeZone::createTimeZone("GMT-3:00"),
4904                             status),
4905                     "yMdHm", "en", status));
4906     if (!assertSuccess("Create with pattern yMMMMd", status)) {
4907         return;
4908     }
4909     UnicodeString result;
4910     FieldPosition pos(FieldPosition::DONT_CARE);
4911 
4912     LocalPointer<Calendar> cal(Calendar::createInstance(
4913         TimeZone::createTimeZone("GMT-7:00"),
4914         status));
4915     if (!assertSuccess("Creating GMT-7 time zone failed", status)) {
4916         return;
4917     }
4918     cal->clear();
4919     cal->set(1998, 5-1, 25, 0, 0, 0);
4920 
4921     // date format time zone should be 4 hours ahead.
4922     fmt->format(cal->getTime(status), result, pos);
4923     assertEquals("format yMdHm", "5/25/1998, 04:00", result);
4924     assertSuccess("", status);
4925 }
4926 
TestDFSCreateForLocaleNonGregorianLocale()4927 void DateFormatTest::TestDFSCreateForLocaleNonGregorianLocale() {
4928     UErrorCode status = U_ZERO_ERROR;
4929     Locale fa("fa");
4930     LocalPointer<DateFormatSymbols> sym(
4931             DateFormatSymbols::createForLocale(fa, status));
4932     if (!assertSuccess("", status)) {
4933         return;
4934     }
4935 
4936     // Android: All locales default to Gregorian calendar:
4937     int32_t count;
4938     const UnicodeString *months = sym->getShortMonths(count);
4939 
4940     // First persian month.
4941     UnicodeString expected("\\u0698\\u0627\\u0646\\u0648\\u06CC\\u0647\\u0654");  // Android-changed
4942     assertEquals("", expected.unescape(), months[0]);
4943 }
4944 
TestDFSCreateForLocaleWithCalendarInLocale()4945 void DateFormatTest::TestDFSCreateForLocaleWithCalendarInLocale() {
4946     UErrorCode status = U_ZERO_ERROR;
4947     Locale en_heb("en@calendar=hebrew");
4948     LocalPointer<DateFormatSymbols> sym(
4949             DateFormatSymbols::createForLocale(en_heb, status));
4950     if (!assertSuccess("", status)) {
4951         return;
4952     }
4953 
4954     // We should get the months of the hebrew calendar, not the gregorian
4955     // calendar.
4956     int32_t count;
4957     const UnicodeString *months = sym->getShortMonths(count);
4958 
4959     // First hebrew month.
4960     UnicodeString expected("Tishri");
4961     assertEquals("", expected, months[0]);
4962 }
4963 
TestChangeCalendar()4964 void DateFormatTest::TestChangeCalendar() {
4965     UErrorCode status = U_ZERO_ERROR;
4966     Locale en("en");
4967     Locale en_heb("en@calendar=hebrew");
4968     LocalPointer<DateFormat> fmt(
4969             DateFormat::createInstanceForSkeleton("yMMMd", en, status));
4970     if (!assertSuccess("", status)) {
4971         return;
4972     }
4973     fmt->adoptCalendar(Calendar::createInstance(en_heb, status));
4974     if (!assertSuccess("", status)) {
4975         return;
4976     }
4977     UnicodeString result;
4978     FieldPosition pos(FieldPosition::DONT_CARE);
4979     fmt->format(date(98, 5-1, 25), result, pos);
4980     assertEquals("format yMMMd", "Iyar 29, 5758", result);
4981 }
4982 
TestPatternFromSkeleton()4983 void DateFormatTest::TestPatternFromSkeleton() {
4984     static const struct {
4985         const Locale& locale;
4986         const char* const skeleton;
4987         const char* const pattern;
4988     } TESTDATA[] = {
4989         // Ticket #11985
4990         {Locale::getEnglish(), "jjmm", "h:mm a"},
4991         {Locale::getEnglish(), "JJmm", "hh:mm"},
4992         {Locale::getGerman(), "jjmm", "HH:mm"},
4993         {Locale::getGerman(), "JJmm", "HH:mm"},
4994         // Ticket #20739
4995         // minutes+milliseconds, seconds missing, should be repaired
4996         {Locale::getEnglish(), "SSSSm", "mm:ss.SSSS"},
4997         {Locale::getEnglish(), "mSSSS", "mm:ss.SSSS"},
4998         {Locale::getEnglish(), "SSSm", "mm:ss.SSS"},
4999         {Locale::getEnglish(), "mSSS", "mm:ss.SSS"},
5000         {Locale::getEnglish(), "SSm", "mm:ss.SS"},
5001         {Locale::getEnglish(), "mSS", "mm:ss.SS"},
5002         {Locale::getEnglish(), "Sm", "mm:ss.S"},
5003         {Locale::getEnglish(), "mS", "mm:ss.S"},
5004         // only milliseconds, untouched, no repairs
5005         {Locale::getEnglish(), "S", "S"},
5006         {Locale::getEnglish(), "SS", "SS"},
5007         {Locale::getEnglish(), "SSS", "SSS"},
5008         {Locale::getEnglish(), "SSSS", "SSSS"},
5009         // hour:minute+seconds+milliseconds, correct, no repairs, proper pattern
5010         {Locale::getEnglish(), "jmsSSS", "h:mm:ss.SSS a"},
5011         {Locale::getEnglish(), "jmSSS", "h:mm:ss.SSS a"},
5012         // Ticket #20738
5013         // seconds+milliseconds, correct, no repairs, proper pattern
5014         {Locale::getEnglish(), "sS", "s.S"},
5015         {Locale::getEnglish(), "sSS", "s.SS"},
5016         {Locale::getEnglish(), "sSSS", "s.SSS"},
5017         {Locale::getEnglish(), "sSSSS", "s.SSSS"},
5018         {Locale::getEnglish(), "sS", "s.S"},
5019         // minutes+seconds+milliseconds, correct, no repairs, proper pattern
5020         {Locale::getEnglish(), "msS", "mm:ss.S"},
5021         {Locale::getEnglish(), "msSS", "mm:ss.SS"},
5022         {Locale::getEnglish(), "msSSS", "mm:ss.SSS"},
5023         {Locale::getEnglish(), "msSSSS", "mm:ss.SSSS"}
5024     };
5025 
5026     for (size_t i = 0; i < UPRV_LENGTHOF(TESTDATA); i++) {
5027         UErrorCode status = U_ZERO_ERROR;
5028         LocalPointer<DateFormat> fmt(
5029                 DateFormat::createInstanceForSkeleton(
5030                         TESTDATA[i].skeleton, TESTDATA[i].locale, status));
5031         if (!assertSuccess("createInstanceForSkeleton", status)) {
5032             return;
5033         }
5034         UnicodeString pattern;
5035         static_cast<const SimpleDateFormat*>(fmt.getAlias())->toPattern(pattern);
5036         assertEquals("Format pattern", TESTDATA[i].pattern, pattern);
5037     }
5038 }
5039 
TestAmPmMidnightNoon()5040 void DateFormatTest::TestAmPmMidnightNoon() {
5041     // Some times on 2015-11-13 (UTC+0).
5042     UDate k000000 = 1447372800000.0;
5043     UDate k000030 = 1447372830000.0;
5044     UDate k003000 = 1447374600000.0;
5045     UDate k060000 = 1447394400000.0;
5046     UDate k120000 = 1447416000000.0;
5047     UDate k180000 = 1447437600000.0;
5048 
5049     UErrorCode errorCode = U_ZERO_ERROR;
5050     SimpleDateFormat sdf(UnicodeString(), errorCode);
5051     if (U_FAILURE(errorCode)) {
5052         dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
5053         return;
5054     }
5055     const TimeZone *tz = TimeZone::getGMT();
5056     sdf.setTimeZone(*tz);
5057     UnicodeString out;
5058 
5059     // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
5060     // For ICU 57 output of "midnight" is temporarily suppressed.
5061 
5062     // Short.
5063     sdf.applyPattern(UnicodeString("hh:mm:ss bbb"));
5064 
5065     // assertEquals("hh:mm:ss bbb | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
5066     assertEquals("hh:mm:ss bbb | 00:00:00", "12:00:00 AM", sdf.format(k000000, out.remove()));
5067     assertEquals("hh:mm:ss bbb | 00:00:30", "12:00:30 AM", sdf.format(k000030, out.remove()));
5068     assertEquals("hh:mm:ss bbb | 00:30:00", "12:30:00 AM", sdf.format(k003000, out.remove()));
5069     assertEquals("hh:mm:ss bbb | 06:00:00", "06:00:00 AM", sdf.format(k060000, out.remove()));
5070     assertEquals("hh:mm:ss bbb | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
5071     assertEquals("hh:mm:ss bbb | 18:00:00", "06:00:00 PM", sdf.format(k180000, out.remove()));
5072 
5073     sdf.applyPattern(UnicodeString("hh:mm bbb"));
5074 
5075     // assertEquals("hh:mm bbb | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
5076     assertEquals("hh:mm bbb | 00:00:00", "12:00 AM", sdf.format(k000000, out.remove()));
5077     // assertEquals("hh:mm bbb | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
5078     assertEquals("hh:mm bbb | 00:00:30", "12:00 AM", sdf.format(k000030, out.remove()));
5079     assertEquals("hh:mm bbb | 00:30:00", "12:30 AM", sdf.format(k003000, out.remove()));
5080 
5081     sdf.applyPattern(UnicodeString("hh bbb"));
5082 
5083     // assertEquals("hh bbb | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
5084     assertEquals("hh bbb | 00:00:00", "12 AM", sdf.format(k000000, out.remove()));
5085     // assertEquals("hh bbb | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
5086     assertEquals("hh bbb | 00:00:30", "12 AM", sdf.format(k000030, out.remove()));
5087     // assertEquals("hh bbb | 00:30:00", "12 midnight", sdf.format(k003000, out.remove()));
5088     assertEquals("hh bbb | 00:30:00", "12 AM", sdf.format(k003000, out.remove()));
5089 
5090     // Wide.
5091     sdf.applyPattern(UnicodeString("hh:mm:ss bbbb"));
5092 
5093     // assertEquals("hh:mm:ss bbbb | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
5094     assertEquals("hh:mm:ss bbbb | 00:00:00", "12:00:00 AM", sdf.format(k000000, out.remove()));
5095     assertEquals("hh:mm:ss bbbb | 00:00:30", "12:00:30 AM", sdf.format(k000030, out.remove()));
5096     assertEquals("hh:mm:ss bbbb | 00:30:00", "12:30:00 AM", sdf.format(k003000, out.remove()));
5097     assertEquals("hh:mm:ss bbbb | 06:00:00", "06:00:00 AM", sdf.format(k060000, out.remove()));
5098     assertEquals("hh:mm:ss bbbb | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
5099     assertEquals("hh:mm:ss bbbb | 18:00:00", "06:00:00 PM", sdf.format(k180000, out.remove()));
5100 
5101     sdf.applyPattern(UnicodeString("hh:mm bbbb"));
5102 
5103     // assertEquals("hh:mm bbbb | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
5104     assertEquals("hh:mm bbbb | 00:00:00", "12:00 AM", sdf.format(k000000, out.remove()));
5105     // assertEquals("hh:mm bbbb | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
5106     assertEquals("hh:mm bbbb | 00:00:30", "12:00 AM", sdf.format(k000030, out.remove()));
5107     assertEquals("hh:mm bbbb | 00:30:00", "12:30 AM", sdf.format(k003000, out.remove()));
5108 
5109     sdf.applyPattern(UnicodeString("hh bbbb"));
5110 
5111     // assertEquals("hh bbbb | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
5112     assertEquals("hh bbbb | 00:00:00", "12 AM", sdf.format(k000000, out.remove()));
5113     // assertEquals("hh bbbb | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
5114     assertEquals("hh bbbb | 00:00:30", "12 AM", sdf.format(k000030, out.remove()));
5115     // assertEquals("hh bbbb | 00:30:00", "12 midnight", sdf.format(k003000, out.remove()));
5116     assertEquals("hh bbbb | 00:30:00", "12 AM", sdf.format(k003000, out.remove()));
5117 
5118     // Narrow.
5119     sdf.applyPattern(UnicodeString("hh:mm:ss bbbbb"));
5120 
5121     // assertEquals("hh:mm:ss bbbbb | 00:00:00", "12:00:00 mi", sdf.format(k000000, out.remove()));
5122     assertEquals("hh:mm:ss bbbbb | 00:00:00", "12:00:00 a", sdf.format(k000000, out.remove()));
5123     assertEquals("hh:mm:ss bbbbb | 00:00:30", "12:00:30 a", sdf.format(k000030, out.remove()));
5124     assertEquals("hh:mm:ss bbbbb | 00:30:00", "12:30:00 a", sdf.format(k003000, out.remove()));
5125     assertEquals("hh:mm:ss bbbbb | 06:00:00", "06:00:00 a", sdf.format(k060000, out.remove()));
5126     assertEquals("hh:mm:ss bbbbb | 12:00:00", "12:00:00 n", sdf.format(k120000, out.remove()));
5127     assertEquals("hh:mm:ss bbbbb | 18:00:00", "06:00:00 p", sdf.format(k180000, out.remove()));
5128 
5129     sdf.applyPattern(UnicodeString("hh:mm bbbbb"));
5130 
5131     // assertEquals("hh:mm bbbbb | 00:00:00", "12:00 mi", sdf.format(k000000, out.remove()));
5132     assertEquals("hh:mm bbbbb | 00:00:00", "12:00 a", sdf.format(k000000, out.remove()));
5133     // assertEquals("hh:mm bbbbb | 00:00:30", "12:00 mi", sdf.format(k000030, out.remove()));
5134     assertEquals("hh:mm bbbbb | 00:00:30", "12:00 a", sdf.format(k000030, out.remove()));
5135     assertEquals("hh:mm bbbbb | 00:30:00", "12:30 a", sdf.format(k003000, out.remove()));
5136 
5137     sdf.applyPattern(UnicodeString("hh bbbbb"));
5138 
5139     // assertEquals("hh bbbbb | 00:00:00", "12 mi", sdf.format(k000000, out.remove()));
5140     assertEquals("hh bbbbb | 00:00:00", "12 a", sdf.format(k000000, out.remove()));
5141     // assertEquals("hh bbbbb | 00:00:30", "12 mi", sdf.format(k000030, out.remove()));
5142     assertEquals("hh bbbbb | 00:00:30", "12 a", sdf.format(k000030, out.remove()));
5143     // assertEquals("hh bbbbb | 00:30:00", "12 mi", sdf.format(k003000, out.remove()));
5144     assertEquals("hh bbbbb | 00:30:00", "12 a", sdf.format(k003000, out.remove()));
5145 }
5146 
TestFlexibleDayPeriod()5147 void DateFormatTest::TestFlexibleDayPeriod() {
5148     // Some times on 2015-11-13 (UTC+0).
5149     UDate k000000 = 1447372800000.0;
5150     UDate k000030 = 1447372830000.0;
5151     UDate k003000 = 1447374600000.0;
5152     UDate k060000 = 1447394400000.0;
5153     UDate k120000 = 1447416000000.0;
5154     UDate k180000 = 1447437600000.0;
5155 
5156     UErrorCode errorCode = U_ZERO_ERROR;
5157     SimpleDateFormat sdf(UnicodeString(), errorCode);
5158     if (U_FAILURE(errorCode)) {
5159         dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
5160         return;
5161     }
5162     const TimeZone *tz = TimeZone::getGMT();
5163     sdf.setTimeZone(*tz);
5164     UnicodeString out;
5165 
5166     // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
5167     // For ICU 57 output of "midnight" is temporarily suppressed.
5168 
5169     // Short.
5170     sdf.applyPattern(UnicodeString("hh:mm:ss BBB"));
5171 
5172     // assertEquals("hh:mm:ss BBB | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
5173     assertEquals("hh:mm:ss BBB | 00:00:00", "12:00:00 at night", sdf.format(k000000, out.remove()));
5174     assertEquals("hh:mm:ss BBB | 00:00:30", "12:00:30 at night", sdf.format(k000030, out.remove()));
5175     assertEquals("hh:mm:ss BBB | 00:30:00", "12:30:00 at night", sdf.format(k003000, out.remove()));
5176     assertEquals("hh:mm:ss BBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000, out.remove()));
5177     assertEquals("hh:mm:ss BBB | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
5178     assertEquals("hh:mm:ss BBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000, out.remove()));
5179 
5180     sdf.applyPattern(UnicodeString("hh:mm BBB"));
5181 
5182     // assertEquals("hh:mm BBB | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
5183     assertEquals("hh:mm BBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
5184     // assertEquals("hh:mm BBB | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
5185     assertEquals("hh:mm BBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
5186     assertEquals("hh:mm BBB | 00:30:00", "12:30 at night", sdf.format(k003000, out.remove()));
5187 
5188     sdf.applyPattern(UnicodeString("hh BBB"));
5189 
5190     // assertEquals("hh BBB | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
5191     assertEquals("hh BBB | 00:00:30", "12 at night", sdf.format(k000030, out.remove()));
5192     // assertEquals("hh BBB | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
5193     assertEquals("hh BBB | 00:00:30", "12 at night", sdf.format(k000030, out.remove()));
5194     // assertEquals("hh BBB | 00:30:00", "12 midnight", sdf.format(k003000, out.remove()));
5195     assertEquals("hh BBB | 00:30:00", "12 at night", sdf.format(k003000, out.remove()));
5196 
5197     // Wide.
5198     sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5199 
5200     // assertEquals("hh:mm:ss BBBB | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
5201     assertEquals("hh:mm:ss BBBB | 00:00:00", "12:00:00 at night", sdf.format(k000000, out.remove()));
5202     assertEquals("hh:mm:ss BBBB | 00:00:30", "12:00:30 at night", sdf.format(k000030, out.remove()));
5203     assertEquals("hh:mm:ss BBBB | 00:30:00", "12:30:00 at night", sdf.format(k003000, out.remove()));
5204     assertEquals("hh:mm:ss BBBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000, out.remove()));
5205     assertEquals("hh:mm:ss BBBB | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
5206     assertEquals("hh:mm:ss BBBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000, out.remove()));
5207 
5208     sdf.applyPattern(UnicodeString("hh:mm BBBB"));
5209 
5210     // assertEquals("hh:mm BBBB | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
5211     assertEquals("hh:mm BBBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
5212     // assertEquals("hh:mm BBBB | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
5213     assertEquals("hh:mm BBBB | 00:00:30", "12:00 at night", sdf.format(k000030, out.remove()));
5214     assertEquals("hh:mm BBBB | 00:30:00", "12:30 at night", sdf.format(k003000, out.remove()));
5215 
5216     sdf.applyPattern(UnicodeString("hh BBBB"));
5217 
5218     // assertEquals("hh BBBB | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
5219     assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
5220     // assertEquals("hh BBBB | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
5221     assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
5222     // assertEquals("hh BBBB | 00:80:00", "12 midnight", sdf.format(k003000, out.remove()));
5223     assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
5224 
5225     // Narrow.
5226     sdf.applyPattern(UnicodeString("hh:mm:ss BBBBB"));
5227 
5228     // assertEquals("hh:mm:ss BBBBB | 00:00:00", "12:00:00 mi", sdf.format(k000000, out.remove()));
5229     assertEquals("hh:mm:ss BBBBB | 00:00:00", "12:00:00 at night", sdf.format(k000000, out.remove()));
5230     assertEquals("hh:mm:ss BBBBB | 00:00:30", "12:00:30 at night", sdf.format(k000030, out.remove()));
5231     assertEquals("hh:mm:ss BBBBB | 00:30:00", "12:30:00 at night", sdf.format(k003000, out.remove()));
5232     assertEquals("hh:mm:ss BBBBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000, out.remove()));
5233     assertEquals("hh:mm:ss BBBBB | 12:00:00", "12:00:00 n", sdf.format(k120000, out.remove()));
5234     assertEquals("hh:mm:ss BBBBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000, out.remove()));
5235 
5236     sdf.applyPattern(UnicodeString("hh:mm BBBBB"));
5237 
5238     // assertEquals("hh:mm BBBBB | 00:00:00", "12:00 mi", sdf.format(k000000, out.remove()));
5239     assertEquals("hh:mm BBBBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
5240     // assertEquals("hh:mm BBBBB | 00:00:30", "12:00 mi", sdf.format(k000030, out.remove()));
5241     assertEquals("hh:mm BBBBB | 00:00:30", "12:00 at night", sdf.format(k000030, out.remove()));
5242     assertEquals("hh:mm BBBBB | 00:30:00", "12:30 at night", sdf.format(k003000, out.remove()));
5243 
5244     sdf.applyPattern(UnicodeString("hh BBBBB"));
5245 
5246     // assertEquals("hh BBBBB | 00:00:00", "12 mi", sdf.format(k000000, out.remove()));
5247     assertEquals("hh BBBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
5248     // assertEquals("hh BBBBB | 00:00:30", "12 mi", sdf.format(k000030, out.remove()));
5249     assertEquals("hh BBBBB | 00:00:30", "12 at night", sdf.format(k000030, out.remove()));
5250     // assertEquals("hh BBBBB | 00:30:00", "12 mi", sdf.format(k003000, out.remove()));
5251     assertEquals("hh BBBBB | 00:30:00", "12 at night", sdf.format(k003000, out.remove()));
5252 }
5253 
TestDayPeriodWithLocales()5254 void DateFormatTest::TestDayPeriodWithLocales() {
5255     // Some times on 2015-11-13 (UTC+0).
5256     UDate k000000 = 1447372800000.0;
5257     UDate k010000 = 1447376400000.0;
5258     UDate k120000 = 1447416000000.0;
5259     UDate k220000 = 1447452000000.0;
5260 
5261     UErrorCode errorCode = U_ZERO_ERROR;
5262     const TimeZone *tz = TimeZone::getGMT();
5263     UnicodeString out;
5264 
5265     // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
5266     // For ICU 57 output of "midnight" and its localized equivalentns is temporarily suppressed.
5267 
5268     // Locale de has a word for midnight, but not noon.
5269     SimpleDateFormat sdf(UnicodeString(), Locale::getGermany(), errorCode);
5270     if (U_FAILURE(errorCode)) {
5271         dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
5272         return;
5273     }
5274     sdf.setTimeZone(*tz);
5275 
5276     sdf.applyPattern(UnicodeString("hh:mm:ss bbbb"));
5277 
5278     // assertEquals("hh:mm:ss bbbb | 00:00:00 | de", "12:00:00 Mitternacht",
5279     //     sdf.format(k000000, out.remove()));
5280     assertEquals("hh:mm:ss bbbb | 00:00:00 | de", "12:00:00 AM",
5281         sdf.format(k000000, out.remove()));
5282     assertEquals("hh:mm:ss bbbb | 12:00:00 | de", "12:00:00 PM",
5283         sdf.format(k120000, out.remove()));
5284 
5285     // Locale ee has a rule that wraps around midnight (21h - 4h).
5286     sdf = SimpleDateFormat(UnicodeString(), Locale("ee"), errorCode);
5287     sdf.setTimeZone(*tz);
5288 
5289     sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5290 
5291     assertEquals("hh:mm:ss BBBB | 22:00:00 | ee", UnicodeString("10:00:00 z\\u00E3").unescape(),
5292         sdf.format(k220000, out.remove()));
5293     assertEquals("hh:mm:ss BBBB | 00:00:00 | ee", UnicodeString("12:00:00 z\\u00E3").unescape(),
5294         sdf.format(k000000, out.remove()));
5295     assertEquals("hh:mm:ss BBBB | 01:00:00 | ee", UnicodeString("01:00:00 z\\u00E3").unescape(),
5296         sdf.format(k010000, out.remove()));
5297 
5298     // Locale root has rules for AM/PM only.
5299     sdf = SimpleDateFormat(UnicodeString(), Locale("root"), errorCode);
5300     sdf.setTimeZone(*tz);
5301 
5302     sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5303 
5304     assertEquals("hh:mm:ss BBBB | 00:00:00 | root", "12:00:00 AM",
5305         sdf.format(k000000, out.remove()));
5306     assertEquals("hh:mm:ss BBBB | 12:00:00 | root", "12:00:00 PM",
5307         sdf.format(k120000, out.remove()));
5308 
5309     // Empty string should behave exactly as root.
5310     sdf = SimpleDateFormat(UnicodeString(), Locale(""), errorCode);
5311     sdf.setTimeZone(*tz);
5312 
5313     sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5314 
5315     assertEquals("hh:mm:ss BBBB | 00:00:00 | \"\" (root)", "12:00:00 AM",
5316         sdf.format(k000000, out.remove()));
5317     assertEquals("hh:mm:ss BBBB | 12:00:00 | \"\" (root)", "12:00:00 PM",
5318         sdf.format(k120000, out.remove()));
5319 
5320     // Locale en_US should fall back to en.
5321     sdf = SimpleDateFormat(UnicodeString(), Locale("en_US"), errorCode);
5322     sdf.setTimeZone(*tz);
5323 
5324     sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5325 
5326     // assertEquals("hh:mm:ss BBBB | 00:00:00 | en_US", "12:00:00 midnight",
5327     //     sdf.format(k000000, out.remove()));
5328     assertEquals("hh:mm:ss BBBB | 00:00:00 | en_US", "12:00:00 at night",
5329          sdf.format(k000000, out.remove()));
5330     assertEquals("hh:mm:ss BBBB | 01:00:00 | en_US", "01:00:00 at night",
5331         sdf.format(k010000, out.remove()));
5332     assertEquals("hh:mm:ss BBBB | 12:00:00 | en_US", "12:00:00 noon",
5333         sdf.format(k120000, out.remove()));
5334 
5335     // Locale es_CO should not fall back to es and should have a
5336     // different string for 1 in the morning.
5337     // (es_CO: "de la manana" (first n has a tilde) vs. es: "de la madrugada")
5338     sdf = SimpleDateFormat(UnicodeString(), Locale("es_CO"), errorCode);
5339     sdf.setTimeZone(*tz);
5340 
5341     sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5342     assertEquals("hh:mm:ss BBBB | 01:00:00 | es_CO", u"01:00:00 de la mañana",
5343         sdf.format(k010000, out.remove()));
5344 
5345     sdf = SimpleDateFormat(UnicodeString(), Locale("es"), errorCode);
5346     sdf.setTimeZone(*tz);
5347 
5348     sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5349     assertEquals("hh:mm:ss BBBB | 01:00:00 | es", "01:00:00 de la madrugada",
5350         sdf.format(k010000, out.remove()));
5351 
5352     // #13215: for locales with keywords, check hang in DayPeriodRules""getInstance(const Locale, ...),
5353     // which is called in SimpleDateFormat::format for patterns that include 'B'.
5354     sdf = SimpleDateFormat(UnicodeString(), Locale("en@calendar=buddhist"), errorCode);
5355     sdf.setTimeZone(*tz);
5356 
5357     sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5358     assertEquals("hh:mm:ss BBBB | 01:00:00 | en@calendar=buddhist", "01:00:00 at night",
5359         sdf.format(k010000, out.remove()));
5360 }
5361 
TestMinuteSecondFieldsInOddPlaces()5362 void DateFormatTest::TestMinuteSecondFieldsInOddPlaces() {
5363     // Some times on 2015-11-13 (UTC+0).
5364     UDate k000000 = 1447372800000.0;
5365     UDate k000030 = 1447372830000.0;
5366     UDate k003000 = 1447374600000.0;
5367     UDate k060030 = 1447394430000.0;
5368     UDate k063000 = 1447396200000.0;
5369 
5370     UErrorCode errorCode = U_ZERO_ERROR;
5371     const TimeZone *tz = TimeZone::getGMT();
5372     UnicodeString out;
5373 
5374     // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
5375     // For ICU 57 output of "midnight" is temporarily suppressed.
5376 
5377     // Seconds field is not present.
5378 
5379     // Apply pattern through constructor to make sure parsePattern() is called during initialization.
5380     SimpleDateFormat sdf(UnicodeString("hh:mm 'ss' bbbb"), errorCode);
5381     if (U_FAILURE(errorCode)) {
5382         dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
5383         return;
5384     }
5385     sdf.setTimeZone(*tz);
5386 
5387     // assertEquals("hh:mm 'ss' bbbb | 00:00:30", "12:00 ss midnight",
5388     //     sdf.format(k000030, out.remove()));
5389     assertEquals("hh:mm 'ss' bbbb | 00:00:30", "12:00 ss AM",
5390         sdf.format(k000030, out.remove()));
5391     assertEquals("hh:mm 'ss' bbbb | 06:00:30", "06:00 ss AM",
5392         sdf.format(k060030, out.remove()));
5393 
5394     sdf.applyPattern(UnicodeString("hh:mm 'ss' BBBB"));
5395 
5396     // assertEquals("hh:mm 'ss' BBBB | 00:00:30", "12:00 ss midnight",
5397     //     sdf.format(k000030, out.remove()));
5398     assertEquals("hh:mm 'ss' BBBB | 00:00:30", "12:00 ss at night",
5399         sdf.format(k000030, out.remove()));
5400     assertEquals("hh:mm 'ss' BBBB | 06:00:30", "06:00 ss in the morning",
5401         sdf.format(k060030, out.remove()));
5402 
5403     // Minutes field is not present.
5404     sdf.applyPattern(UnicodeString("hh 'mm ss' bbbb"));
5405 
5406     // assertEquals("hh 'mm ss' bbbb | 00:30:00", "12 mm ss midnight",
5407     //     sdf.format(k003000, out.remove()));
5408     assertEquals("hh 'mm ss' bbbb | 00:30:00", "12 mm ss AM",
5409         sdf.format(k003000, out.remove()));
5410     assertEquals("hh 'mm ss' bbbb | 06:30:00", "06 mm ss AM",
5411         sdf.format(k063000, out.remove()));
5412 
5413     sdf.applyPattern(UnicodeString("hh 'mm ss' BBBB"));
5414 
5415     // assertEquals("hh 'mm ss' BBBB | 00:30:00", "12 mm ss midnight",
5416     //     sdf.format(k003000, out.remove()));
5417     assertEquals("hh 'mm ss' BBBB | 00:30:00", "12 mm ss at night",
5418         sdf.format(k003000, out.remove()));
5419     assertEquals("hh 'mm ss' BBBB | 06:30:00", "06 mm ss in the morning",
5420         sdf.format(k063000, out.remove()));
5421 
5422     // Minutes and seconds fields appear after day periods.
5423     sdf.applyPattern(UnicodeString("bbbb hh:mm:ss"));
5424 
5425     // assertEquals("bbbb hh:mm:ss | 00:00:00", "midnight 12:00:00",
5426     //     sdf.format(k000000, out.remove()));
5427     assertEquals("bbbb hh:mm:ss | 00:00:00", "AM 12:00:00",
5428         sdf.format(k000000, out.remove()));
5429     assertEquals("bbbb hh:mm:ss | 00:00:30", "AM 12:00:30",
5430         sdf.format(k000030, out.remove()));
5431     assertEquals("bbbb hh:mm:ss | 00:30:00", "AM 12:30:00",
5432         sdf.format(k003000, out.remove()));
5433 
5434     sdf.applyPattern(UnicodeString("BBBB hh:mm:ss"));
5435 
5436     // assertEquals("BBBB hh:mm:ss | 00:00:00", "midnight 12:00:00",
5437     //     sdf.format(k000000, out.remove()));
5438     assertEquals("BBBB hh:mm:ss | 00:00:00", "at night 12:00:00",
5439         sdf.format(k000000, out.remove()));
5440     assertEquals("BBBB hh:mm:ss | 00:00:30", "at night 12:00:30",
5441         sdf.format(k000030, out.remove()));
5442     assertEquals("BBBB hh:mm:ss | 00:30:00", "at night 12:30:00",
5443         sdf.format(k003000, out.remove()));
5444 
5445     // Confirm applyPattern() reparses the pattern string.
5446     sdf.applyPattern(UnicodeString("BBBB hh"));
5447     // assertEquals("BBBB hh | 00:00:30", "midnight 12",
5448     //     sdf.format(k000030, out.remove()));
5449     assertEquals("BBBB hh | 00:00:30", "at night 12",
5450          sdf.format(k000030, out.remove()));
5451 
5452     sdf.applyPattern(UnicodeString("BBBB hh:mm:'ss'"));
5453     // assertEquals("BBBB hh:mm:'ss' | 00:00:30", "midnight 12:00:ss",
5454     //     sdf.format(k000030, out.remove()));
5455     assertEquals("BBBB hh | 00:00:30", "at night 12:00:ss",
5456         sdf.format(k000030, out.remove()));
5457 
5458     sdf.applyPattern(UnicodeString("BBBB hh:mm:ss"));
5459     assertEquals("BBBB hh:mm:ss | 00:00:30", "at night 12:00:30",
5460         sdf.format(k000030, out.remove()));
5461 }
5462 
TestDayPeriodParsing()5463 void DateFormatTest::TestDayPeriodParsing() {
5464     // Some times on 2015-11-13 (UTC+0).
5465     UDate k000000 = 1447372800000.0;
5466     UDate k003700 = 1447375020000.0;
5467     UDate k010000 = 1447376400000.0;
5468     UDate k013000 = 1447378200000.0;
5469     UDate k030000 = 1447383600000.0;
5470     UDate k090000 = 1447405200000.0;
5471     UDate k120000 = 1447416000000.0;
5472     UDate k130000 = 1447419600000.0;
5473     UDate k133700 = 1447421820000.0;
5474     UDate k150000 = 1447426800000.0;
5475     UDate k190000 = 1447441200000.0;
5476     UDate k193000 = 1447443000000.0;
5477     UDate k200000 = 1447444800000.0;
5478     UDate k210000 = 1447448400000.0;
5479 
5480     UErrorCode errorCode = U_ZERO_ERROR;
5481     SimpleDateFormat sdf(UnicodeString(), errorCode);
5482     if (U_FAILURE(errorCode)) {
5483         dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
5484         return;
5485     }
5486     const TimeZone *tz = TimeZone::getGMT();
5487     sdf.setTimeZone(*tz);
5488     UnicodeString out;
5489 
5490     // 'B' -- flexible day periods
5491     // A day period on its own parses to the center of that period.
5492     sdf.applyPattern(UnicodeString("yyyy-MM-dd B"));
5493     assertEquals("yyyy-MM-dd B | 2015-11-13 midnight",
5494         k000000, sdf.parse(UnicodeString("2015-11-13 midnight"), errorCode));
5495     assertEquals("yyyy-MM-dd B | 2015-11-13 noon",
5496         k120000, sdf.parse(UnicodeString("2015-11-13 noon"), errorCode));
5497     assertEquals("yyyy-MM-dd B | 2015-11-13 in the afternoon",
5498         k150000, sdf.parse(UnicodeString("2015-11-13 in the afternoon"), errorCode));
5499     assertEquals("yyyy-MM-dd B | 2015-11-13 in the evening",
5500         k193000, sdf.parse(UnicodeString("2015-11-13 in the evening"), errorCode));
5501     assertEquals("yyyy-MM-dd B | 2015-11-13 at night",
5502         k013000, sdf.parse(UnicodeString("2015-11-13 at night"), errorCode));
5503 
5504     // If time and day period are consistent with each other then time is parsed accordingly.
5505     sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm B"));
5506     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 12:00 midnight",
5507         k000000, sdf.parse(UnicodeString("2015-11-13 12:00 midnight"), errorCode));
5508     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 12:00 noon",
5509         k120000, sdf.parse(UnicodeString("2015-11-13 12:00 noon"), errorCode));
5510     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 01:00 at night",
5511         k010000, sdf.parse(UnicodeString("2015-11-13 01:00 at night"), errorCode));
5512     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 01:00 in the afternoon",
5513         k130000, sdf.parse(UnicodeString("2015-11-13 01:00 in the afternoon"), errorCode));
5514     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 09:00 in the morning",
5515         k090000, sdf.parse(UnicodeString("2015-11-13 09:00 in the morning"), errorCode));
5516     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 09:00 at night",
5517         k210000, sdf.parse(UnicodeString("2015-11-13 09:00 at night"), errorCode));
5518 
5519     // If the hour is 13 thru 23 then day period has no effect on time (since time is assumed
5520     // to be in 24-hour format).
5521     sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm B"));
5522     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 midnight",
5523         k133700, sdf.parse(UnicodeString("2015-11-13 13:37 midnight"), errorCode));
5524     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 noon",
5525         k133700, sdf.parse(UnicodeString("2015-11-13 13:37 noon"), errorCode));
5526     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 at night",
5527         k133700, sdf.parse(UnicodeString("2015-11-13 13:37 at night"), errorCode));
5528     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 in the afternoon",
5529         k133700, sdf.parse(UnicodeString("2015-11-13 13:37 in the afternoon"), errorCode));
5530     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 in the morning",
5531         k133700, sdf.parse(UnicodeString("2015-11-13 13:37 in the morning"), errorCode));
5532     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 at night",
5533         k133700, sdf.parse(UnicodeString("2015-11-13 13:37 at night"), errorCode));
5534 
5535     // Hour 0 is synonymous with hour 12 when parsed with 'h'.
5536     // This unfortunately means we have to tolerate "0 noon" as it's synonymous with "12 noon".
5537     sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm B"));
5538     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 00:00 midnight",
5539         k000000, sdf.parse(UnicodeString("2015-11-13 00:00 midnight"), errorCode));
5540     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 00:00 noon",
5541         k120000, sdf.parse(UnicodeString("2015-11-13 00:00 noon"), errorCode));
5542 
5543     // But when parsed with 'H', 0 indicates a 24-hour time, therefore we disregard the day period.
5544     sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm B"));
5545     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 midnight",
5546         k003700, sdf.parse(UnicodeString("2015-11-13 00:37 midnight"), errorCode));
5547     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 noon",
5548         k003700, sdf.parse(UnicodeString("2015-11-13 00:37 noon"), errorCode));
5549     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 at night",
5550         k003700, sdf.parse(UnicodeString("2015-11-13 00:37 at night"), errorCode));
5551     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 in the afternoon",
5552         k003700, sdf.parse(UnicodeString("2015-11-13 00:37 in the afternoon"), errorCode));
5553     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 in the morning",
5554         k003700, sdf.parse(UnicodeString("2015-11-13 00:37 in the morning"), errorCode));
5555     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 at night",
5556         k003700, sdf.parse(UnicodeString("2015-11-13 00:37 at night"), errorCode));
5557 
5558     // Even when parsed with 'H', hours 1 thru 12 are considered 12-hour time and takes
5559     // day period into account in parsing.
5560     sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm B"));
5561     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 12:00 midnight",
5562         k000000, sdf.parse(UnicodeString("2015-11-13 12:00 midnight"), errorCode));
5563     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 12:00 noon",
5564         k120000, sdf.parse(UnicodeString("2015-11-13 12:00 noon"), errorCode));
5565     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 01:00 at night",
5566         k010000, sdf.parse(UnicodeString("2015-11-13 01:00 at night"), errorCode));
5567     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 01:00 in the afternoon",
5568         k130000, sdf.parse(UnicodeString("2015-11-13 01:00 in the afternoon"), errorCode));
5569     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 09:00 in the morning",
5570         k090000, sdf.parse(UnicodeString("2015-11-13 09:00 in the morning"), errorCode));
5571     assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 09:00 at night",
5572         k210000, sdf.parse(UnicodeString("2015-11-13 09:00 at night"), errorCode));
5573 
5574     // If a 12-hour time and the day period don't agree with each other, time is parsed as close
5575     // to the given day period as possible.
5576     sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm B"));
5577 
5578     // AFTERNOON1 is [12, 18), but "7 in the afternoon" parses to 19:00.
5579     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 07:00 in the afternoon",
5580         k190000, sdf.parse(UnicodeString("2015-11-13 07:00 in the afternoon"), errorCode));
5581     // NIGHT1 is [21, 6), but "8 at night" parses to 20:00.
5582     assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 08:00 at night",
5583         k200000, sdf.parse(UnicodeString("2015-11-13 08:00 at night"), errorCode));
5584 
5585     // 'b' -- fixed day periods (AM, PM, midnight, noon)
5586     // On their own, "midnight" parses to 00:00 and "noon" parses to 12:00.
5587     // AM and PM are handled by the 'a' parser (which doesn't handle this case well).
5588     sdf.applyPattern(UnicodeString("yyyy-MM-dd b"));
5589     assertEquals("yyyy-MM-dd b | 2015-11-13 midnight",
5590         k000000, sdf.parse(UnicodeString("2015-11-13 midnight"), errorCode));
5591     assertEquals("yyyy-MM-dd b | 2015-11-13 noon",
5592         k120000, sdf.parse(UnicodeString("2015-11-13 noon"), errorCode));
5593 
5594     // For 12-hour times, AM and PM should be parsed as if with pattern character 'a'.
5595     sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm b"));
5596     assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 01:00 AM",
5597         k010000, sdf.parse(UnicodeString("2015-11-13 01:00 AM"), errorCode));
5598     assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 01:00 PM",
5599         k130000, sdf.parse(UnicodeString("2015-11-13 01:00 PM"), errorCode));
5600 
5601     // 12 midnight parses to 00:00, and 12 noon parses to 12:00.
5602     assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 12:00 midnight",
5603         k000000, sdf.parse(UnicodeString("2015-11-13 12:00 midnight"), errorCode));
5604     assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 12:00 noon",
5605         k120000, sdf.parse(UnicodeString("2015-11-13 12:00 noon"), errorCode));
5606 
5607     // Hours 13-23 indicate 24-hour time so we disregard "midnight" or "noon".
5608     // Again, AM and PM are handled by the 'a' parser which doesn't handle this case well.
5609     sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm b"));
5610     assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 13:37 midnight",
5611         k133700, sdf.parse(UnicodeString("2015-11-13 13:37 midnight"), errorCode));
5612     assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 13:37 noon",
5613         k133700, sdf.parse(UnicodeString("2015-11-13 13:37 noon"), errorCode));
5614 
5615     // Hour 0 is synonymous with hour 12 when parsed with 'h'.
5616     // Again, this means we have to tolerate "0 noon" as it's synonymous with "12 noon".
5617     sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm b"));
5618     assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 00:00 midnight",
5619         k000000, sdf.parse(UnicodeString("2015-11-13 00:00 midnight"), errorCode));
5620     assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 00:00 noon",
5621         k120000, sdf.parse(UnicodeString("2015-11-13 00:00 noon"), errorCode));
5622 
5623     // With 'H' though 0 indicates a 24-hour time, therefore we disregard the day period.
5624     sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm b"));
5625     assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 00:37 midnight",
5626         k003700, sdf.parse(UnicodeString("2015-11-13 00:37 midnight"), errorCode));
5627     assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 00:37 noon",
5628         k003700, sdf.parse(UnicodeString("2015-11-13 00:37 noon"), errorCode));
5629 
5630     // If "midnight" or "noon" is parsed with a 12-hour time other than 12:00, choose
5631     // the version that's closer to the period given.
5632     sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm b"));
5633     assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 03:00 midnight",
5634         k030000, sdf.parse(UnicodeString("2015-11-13 03:00 midnight"), errorCode));
5635     assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 03:00 noon",
5636         k150000, sdf.parse(UnicodeString("2015-11-13 03:00 noon"), errorCode));
5637 }
5638 
TestParseRegression13744()5639 void DateFormatTest::TestParseRegression13744() {
5640     LocalPointer<DateFormat> dfmt(DateFormat::createDateTimeInstance(
5641             DateFormat::SHORT, DateFormat::SHORT, Locale("en", "US")));
5642     if (dfmt.isNull()) {
5643         dataerrln("DateFormat::createDateTimeInstance() failed");
5644         return;
5645     }
5646     ParsePosition pos(0);
5647     UnicodeString inDate("4/27/18");
5648     dfmt->parse(inDate, pos);
5649     assertEquals("Error index", inDate.length(), pos.getErrorIndex());
5650 }
5651 
TestAdoptCalendarLeak()5652 void DateFormatTest::TestAdoptCalendarLeak() {
5653     UErrorCode status = U_ZERO_ERROR;
5654     // This test relies on the locale fullName exceeding ULOC_FULLNAME_CAPACITY
5655     // in order for setKeywordValue to fail.
5656     Calendar* cal = Calendar::createInstance(status);
5657     ASSERT_OK(status);
5658     SimpleDateFormat sdf(
5659         "d.M.y",
5660         Locale("de__POSIX@colstrength=primary;currency=eur;em=default;"
5661                "hours=h23;lb=strict;lw=normal;measure=metric;numbers=latn;"
5662                "rg=atzzzz;sd=atat1;ss=none;timezone=Europe/Vienna"),
5663         status);
5664     // ASSERT_OK(status); Please do NOT add ASSERT_OK here. The point of this
5665     // test is to ensure sdf.adoptCalendar won't leak AFTER the above FAILED.
5666     // If the following caused crash we should fix the implementation not change
5667     // this test.
5668     sdf.adoptCalendar(cal);
5669 }
5670 
5671 /**
5672  * Test that 'a' and 'B' fields are not duplicated in the field position iterator.
5673  */
Test20741_ABFields()5674 void DateFormatTest::Test20741_ABFields() {
5675     IcuTestErrorCode status(*this, "Test20741_ABFields");
5676 
5677     const char16_t timeZone[] = u"PST8PDT";
5678 
5679     UnicodeString skeletons[] = {u"EEEEEBBBBB", u"EEEEEbbbbb"};
5680 
5681     for (int32_t j = 0; j < 2; j++) {
5682         UnicodeString skeleton = skeletons[j];
5683 
5684         int32_t count = 0;
5685         const Locale* locales = Locale::getAvailableLocales(count);
5686         for (int32_t i = 0; i < count; i++) {
5687             if (quick && (i % 17) != 0) { continue; }
5688 
5689             const Locale locale = locales[i];
5690             LocalPointer<DateTimePatternGenerator> gen(DateTimePatternGenerator::createInstance(locale, status));
5691             UnicodeString pattern = gen->getBestPattern(skeleton, status);
5692 
5693             SimpleDateFormat dateFormat(pattern, locale, status);
5694             FieldPositionIterator fpositer;
5695             UnicodeString result;
5696             LocalPointer<Calendar> calendar(Calendar::createInstance(TimeZone::createTimeZone(timeZone), status));
5697             calendar->setTime(UDate(0), status);
5698             dateFormat.format(*calendar, result, &fpositer, status);
5699 
5700             FieldPosition curFieldPosition;
5701             FieldPosition lastFieldPosition;
5702             lastFieldPosition.setBeginIndex(-1);
5703             lastFieldPosition.setEndIndex(-1);
5704             while(fpositer.next(curFieldPosition)) {
5705                 assertFalse("Field missing on pattern", pattern.indexOf(PATTERN_CHARS[curFieldPosition.getField()]) == -1);
5706                 if (curFieldPosition.getBeginIndex() == lastFieldPosition.getBeginIndex() && curFieldPosition.getEndIndex() == lastFieldPosition.getEndIndex()) {
5707                     assertEquals("Different fields at same position", PATTERN_CHARS[curFieldPosition.getField()], PATTERN_CHARS[lastFieldPosition.getField()]);
5708                 }
5709 
5710                 lastFieldPosition = curFieldPosition;
5711             }
5712         }
5713     }
5714 }
5715 
5716 #endif /* #if !UCONFIG_NO_FORMATTING */
5717 
5718 //eof
5719