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