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