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