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