1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4 * COPYRIGHT:
5 * Copyright (c) 1997-2016, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 ********************************************************************/
8
9 #include "unicode/utypes.h"
10
11 #if !UCONFIG_NO_FORMATTING
12
13 #include "dtfmttst.h"
14 #include "unicode/localpointer.h"
15 #include "unicode/timezone.h"
16 #include "unicode/gregocal.h"
17 #include "unicode/smpdtfmt.h"
18 #include "unicode/datefmt.h"
19 #include "unicode/dtptngen.h"
20 #include "unicode/simpletz.h"
21 #include "unicode/strenum.h"
22 #include "unicode/dtfmtsym.h"
23 #include "unicode/ustring.h"
24 #include "cmemory.h"
25 #include "cstring.h"
26 #include "caltest.h" // for fieldName
27 #include <stdio.h> // for snprintf
28
29 #if U_PLATFORM_USES_ONLY_WIN32_API
30 #include "windttst.h"
31 #endif
32
33 #define ASSERT_OK(status) UPRV_BLOCK_MACRO_BEGIN { \
34 if(U_FAILURE(status)) { \
35 errcheckln(status, #status " = %s @ %s:%d", u_errorName(status), __FILE__, __LINE__); \
36 return; \
37 } \
38 } UPRV_BLOCK_MACRO_END
39
40 // *****************************************************************************
41 // class DateFormatTest
42 // *****************************************************************************
43
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)44 void DateFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
45 {
46 if(exec) {
47 logln("TestSuite DateFormatTest: ");
48 }
49 TESTCASE_AUTO_BEGIN;
50 TESTCASE_AUTO(TestPatterns);
51 TESTCASE_AUTO(TestEquals);
52 TESTCASE_AUTO(TestTwoDigitYearDSTParse);
53 TESTCASE_AUTO(TestFieldPosition);
54 TESTCASE_AUTO(TestPartialParse994);
55 TESTCASE_AUTO(TestRunTogetherPattern985);
56 TESTCASE_AUTO(TestRunTogetherPattern917);
57 TESTCASE_AUTO(TestCzechMonths459);
58 TESTCASE_AUTO(TestLetterDPattern212);
59 TESTCASE_AUTO(TestDayOfYearPattern195);
60 TESTCASE_AUTO(TestQuotePattern161);
61 TESTCASE_AUTO(TestBadInput135);
62 TESTCASE_AUTO(TestBadInput135a);
63 TESTCASE_AUTO(TestTwoDigitYear);
64 TESTCASE_AUTO(TestDateFormatZone061);
65 TESTCASE_AUTO(TestDateFormatZone146);
66 TESTCASE_AUTO(TestLocaleDateFormat);
67 TESTCASE_AUTO(TestFormattingLocaleTimeSeparator);
68 TESTCASE_AUTO(TestWallyWedel);
69 TESTCASE_AUTO(TestDateFormatCalendar);
70 TESTCASE_AUTO(TestSpaceParsing);
71 TESTCASE_AUTO(TestExactCountFormat);
72 TESTCASE_AUTO(TestWhiteSpaceParsing);
73 TESTCASE_AUTO(TestInvalidPattern);
74 TESTCASE_AUTO(TestGeneral);
75 TESTCASE_AUTO(TestGreekMay);
76 TESTCASE_AUTO(TestGenericTime);
77 TESTCASE_AUTO(TestGenericTimeZoneOrder);
78 TESTCASE_AUTO(TestHost);
79 TESTCASE_AUTO(TestEras);
80 TESTCASE_AUTO(TestNarrowNames);
81 TESTCASE_AUTO(TestShortDays);
82 TESTCASE_AUTO(TestStandAloneDays);
83 TESTCASE_AUTO(TestStandAloneMonths);
84 TESTCASE_AUTO(TestQuarters);
85 TESTCASE_AUTO(TestZTimeZoneParsing);
86 TESTCASE_AUTO(TestRelative);
87 TESTCASE_AUTO(TestRelativeClone);
88 TESTCASE_AUTO(TestHostClone);
89 TESTCASE_AUTO(TestHebrewClone);
90 TESTCASE_AUTO(TestDateFormatSymbolsClone);
91 TESTCASE_AUTO(TestTimeZoneDisplayName);
92 TESTCASE_AUTO(TestTimeZoneInLocale);
93 TESTCASE_AUTO(TestRoundtripWithCalendar);
94 TESTCASE_AUTO(Test6338);
95 TESTCASE_AUTO(Test6726);
96 TESTCASE_AUTO(TestGMTParsing);
97 TESTCASE_AUTO(Test6880);
98 TESTCASE_AUTO(TestISOEra);
99 TESTCASE_AUTO(TestFormalChineseDate);
100 TESTCASE_AUTO(TestNumberAsStringParsing);
101 TESTCASE_AUTO(TestStandAloneGMTParse);
102 TESTCASE_AUTO(TestParsePosition);
103 TESTCASE_AUTO(TestMonthPatterns);
104 TESTCASE_AUTO(TestContext);
105 TESTCASE_AUTO(TestNonGregoFmtParse);
106 TESTCASE_AUTO(TestFormatsWithNumberSystems);
107 /*
108 TESTCASE_AUTO(TestRelativeError);
109 TESTCASE_AUTO(TestRelativeOther);
110 */
111 TESTCASE_AUTO(TestDotAndAtLeniency);
112 TESTCASE_AUTO(TestDateFormatLeniency);
113 TESTCASE_AUTO(TestParseMultiPatternMatch);
114
115 TESTCASE_AUTO(TestParseLeniencyAPIs);
116 TESTCASE_AUTO(TestNumberFormatOverride);
117 TESTCASE_AUTO(TestCreateInstanceForSkeleton);
118 TESTCASE_AUTO(TestCreateInstanceForSkeletonDefault);
119 TESTCASE_AUTO(TestCreateInstanceForSkeletonWithCalendar);
120 TESTCASE_AUTO(TestDFSCreateForLocaleNonGregorianLocale);
121 TESTCASE_AUTO(TestDFSCreateForLocaleWithCalendarInLocale);
122 TESTCASE_AUTO(TestChangeCalendar);
123
124 TESTCASE_AUTO(TestPatternFromSkeleton);
125
126 TESTCASE_AUTO(TestAmPmMidnightNoon);
127 TESTCASE_AUTO(TestFlexibleDayPeriod);
128 TESTCASE_AUTO(TestDayPeriodWithLocales);
129 TESTCASE_AUTO(TestMinuteSecondFieldsInOddPlaces);
130 TESTCASE_AUTO(TestDayPeriodParsing);
131 TESTCASE_AUTO(TestParseRegression13744);
132 TESTCASE_AUTO(TestAdoptCalendarLeak);
133 TESTCASE_AUTO(Test20741_ABFields);
134 TESTCASE_AUTO(Test22023_UTCWithMinusZero);
135 TESTCASE_AUTO(TestNumericFieldStrictParse);
136
137 TESTCASE_AUTO_END;
138 }
139
TestPatterns()140 void DateFormatTest::TestPatterns() {
141 static const struct {
142 const char *actualPattern;
143 const char *expectedPattern;
144 const char *localeID;
145 const char16_t *expectedLocalPattern;
146 } EXPECTED[] = {
147 {UDAT_YEAR, "y", "en",u"y"},
148
149 {UDAT_QUARTER, "QQQQ", "en", u"QQQQ"},
150 {UDAT_ABBR_QUARTER, "QQQ", "en", u"QQQ"},
151 {UDAT_YEAR_QUARTER, "yQQQQ", "en", u"QQQQ y"},
152 {UDAT_YEAR_ABBR_QUARTER, "yQQQ", "en", u"QQQ y"},
153
154 {UDAT_NUM_MONTH, "M", "en", u"L"},
155 {UDAT_ABBR_MONTH, "MMM", "en", u"LLL"},
156 {UDAT_MONTH, "MMMM", "en", u"LLLL"},
157 {UDAT_YEAR_NUM_MONTH, "yM","en",u"M/y"},
158 {UDAT_YEAR_ABBR_MONTH, "yMMM","en",u"MMM y"},
159 {UDAT_YEAR_MONTH, "yMMMM","en",u"MMMM y"},
160
161 {UDAT_DAY, "d","en",u"d"},
162 {UDAT_YEAR_NUM_MONTH_DAY, "yMd", "en", u"M/d/y"},
163 {UDAT_YEAR_ABBR_MONTH_DAY, "yMMMd", "en", u"MMM d, y"},
164 {UDAT_YEAR_MONTH_DAY, "yMMMMd", "en", u"MMMM d, y"},
165 {UDAT_YEAR_NUM_MONTH_WEEKDAY_DAY, "yMEd", "en", u"EEE, M/d/y"},
166 {UDAT_YEAR_ABBR_MONTH_WEEKDAY_DAY, "yMMMEd", "en", u"EEE, MMM d, y"},
167 {UDAT_YEAR_MONTH_WEEKDAY_DAY, "yMMMMEEEEd", "en", u"EEEE, MMMM d, y"},
168
169 {UDAT_NUM_MONTH_DAY, "Md","en",u"M/d"},
170 {UDAT_ABBR_MONTH_DAY, "MMMd","en",u"MMM d"},
171 {UDAT_MONTH_DAY, "MMMMd","en",u"MMMM d"},
172 {UDAT_NUM_MONTH_WEEKDAY_DAY, "MEd","en",u"EEE, M/d"},
173 {UDAT_ABBR_MONTH_WEEKDAY_DAY, "MMMEd","en",u"EEE, MMM d"},
174 {UDAT_MONTH_WEEKDAY_DAY, "MMMMEEEEd","en",u"EEEE, MMMM d"},
175
176 {UDAT_HOUR, "j", "en", u"h\u202Fa"}, // (fixed expected result per ticket 6872<-6626)
177 {UDAT_HOUR24, "H", "en", u"HH"}, // (fixed expected result per ticket 6872<-6626
178
179 {UDAT_MINUTE, "m", "en", u"m"},
180 {UDAT_HOUR_MINUTE, "jm","en",u"h:mm\u202Fa"}, // (fixed expected result per ticket 6872<-7180)
181 {UDAT_HOUR24_MINUTE, "Hm", "en", u"HH:mm"}, // (fixed expected result per ticket 6872<-6626)
182
183 {UDAT_SECOND, "s", "en", u"s"},
184 {UDAT_HOUR_MINUTE_SECOND, "jms","en",u"h:mm:ss\u202Fa"}, // (fixed expected result per ticket 6872<-7180)
185 {UDAT_HOUR24_MINUTE_SECOND, "Hms","en",u"HH:mm:ss"}, // (fixed expected result per ticket 6872<-6626)
186 {UDAT_MINUTE_SECOND, "ms", "en", u"mm:ss"}, // (fixed expected result per ticket 6872<-6626)
187
188 {UDAT_LOCATION_TZ, "VVVV", "en", u"VVVV"},
189 {UDAT_GENERIC_TZ, "vvvv", "en", u"vvvv"},
190 {UDAT_ABBR_GENERIC_TZ, "v", "en", u"v"},
191 {UDAT_SPECIFIC_TZ, "zzzz", "en", u"zzzz"},
192 {UDAT_ABBR_SPECIFIC_TZ, "z", "en", u"z"},
193 {UDAT_ABBR_UTC_TZ, "ZZZZ", "en", u"ZZZZ"},
194
195 {UDAT_YEAR_NUM_MONTH_DAY UDAT_ABBR_UTC_TZ, "yMdZZZZ", "en", u"M/d/y, ZZZZ"},
196 {UDAT_MONTH_DAY UDAT_LOCATION_TZ, "MMMMdVVVV", "en", u"MMMM d 'at' VVVV"}
197 };
198
199 IcuTestErrorCode errorCode(*this, "TestPatterns()");
200 for (int32_t i = 0; i < UPRV_LENGTHOF(EXPECTED); i++) {
201 // Verify that patterns have the correct values
202 UnicodeString actualPattern(EXPECTED[i].actualPattern, -1, US_INV);
203 UnicodeString expectedPattern(EXPECTED[i].expectedPattern, -1, US_INV);
204 Locale locale(EXPECTED[i].localeID);
205 if (actualPattern != expectedPattern) {
206 errln("FAILURE! Expected pattern: " + expectedPattern +
207 " but was: " + actualPattern);
208 }
209
210 // Verify that DataFormat instances produced contain the correct
211 // localized patterns
212 // TODO: use DateFormat::getInstanceForSkeleton(), ticket #9029
213 // Java test code:
214 // DateFormat date1 = DateFormat.getPatternInstance(actualPattern,
215 // locale);
216 // DateFormat date2 = DateFormat.getPatternInstance(Calendar.getInstance(locale),
217 // actualPattern, locale);
218 LocalPointer<DateTimePatternGenerator> generator(
219 DateTimePatternGenerator::createInstance(locale, errorCode));
220 if(errorCode.errDataIfFailureAndReset("DateTimePatternGenerator::createInstance() failed for locale ID \"%s\"", EXPECTED[i].localeID)) {
221 continue;
222 }
223 UnicodeString pattern = generator->getBestPattern(actualPattern, errorCode);
224 SimpleDateFormat date1(pattern, locale, errorCode);
225 SimpleDateFormat date2(pattern, locale, errorCode);
226 date2.adoptCalendar(Calendar::createInstance(locale, errorCode));
227 if(errorCode.errIfFailureAndReset("DateFormat::getInstanceForSkeleton() failed")) {
228 errln(" for actualPattern \"%s\" & locale ID \"%s\"",
229 EXPECTED[i].actualPattern, EXPECTED[i].localeID);
230 continue;
231 }
232
233 UnicodeString expectedLocalPattern(EXPECTED[i].expectedLocalPattern, -1);
234 UnicodeString actualLocalPattern1;
235 UnicodeString actualLocalPattern2;
236 date1.toLocalizedPattern(actualLocalPattern1, errorCode);
237 date2.toLocalizedPattern(actualLocalPattern2, errorCode);
238 if (actualLocalPattern1 != expectedLocalPattern) {
239 errln("FAILURE! Expected local pattern: " + expectedLocalPattern
240 + " but was: " + actualLocalPattern1);
241 }
242 if (actualLocalPattern2 != expectedLocalPattern) {
243 errln("FAILURE! Expected local pattern: " + expectedLocalPattern
244 + " but was: " + actualLocalPattern2);
245 }
246 }
247 }
248
249 // Test written by Wally Wedel and emailed to me.
TestWallyWedel()250 void DateFormatTest::TestWallyWedel()
251 {
252 UErrorCode status = U_ZERO_ERROR;
253 /*
254 * Instantiate a TimeZone so we can get the ids.
255 */
256 TimeZone *tz = new SimpleTimeZone(7,"");
257 /*
258 * Computational variables.
259 */
260 int32_t offset, hours, minutes, seconds;
261 /*
262 * Instantiate a SimpleDateFormat set up to produce a full time
263 zone name.
264 */
265 SimpleDateFormat *sdf = new SimpleDateFormat((UnicodeString)"zzzz", status);
266 /*
267 * A String array for the time zone ids.
268 */
269 int32_t ids_length;
270 StringEnumeration* ids = TimeZone::createEnumeration(status);
271 if (U_FAILURE(status)) {
272 dataerrln("Unable to create TimeZone enumeration.");
273 if (sdf != nullptr) {
274 delete sdf;
275 }
276 return;
277 }
278 ids_length = ids->count(status);
279 /*
280 * How many ids do we have?
281 */
282 logln("Time Zone IDs size: %d", ids_length);
283 /*
284 * Column headings (sort of)
285 */
286 logln("Ordinal ID offset(h:m) name");
287 /*
288 * Loop through the tzs.
289 */
290 UDate today = Calendar::getNow();
291 Calendar *cal = Calendar::createInstance(status);
292 for (int32_t i = 0; i < ids_length; i++) {
293 // logln(i + " " + ids[i]);
294 const UnicodeString* id = ids->snext(status);
295 TimeZone *ttz = TimeZone::createTimeZone(*id);
296 // offset = ttz.getRawOffset();
297 cal->setTimeZone(*ttz);
298 cal->setTime(today, status);
299 offset = cal->get(UCAL_ZONE_OFFSET, status) + cal->get(UCAL_DST_OFFSET, status);
300 // logln(i + " " + ids[i] + " offset " + offset);
301 const char* sign = "+";
302 if (offset < 0) {
303 sign = "-";
304 offset = -offset;
305 }
306 hours = offset/3600000;
307 minutes = (offset%3600000)/60000;
308 seconds = (offset%60000)/1000;
309 UnicodeString dstOffset = (UnicodeString)"" + sign + (hours < 10 ? "0" : "") +
310 (int32_t)hours + ":" + (minutes < 10 ? "0" : "") + (int32_t)minutes;
311 if (seconds != 0) {
312 dstOffset = dstOffset + ":" + (seconds < 10 ? "0" : "") + seconds;
313 }
314 /*
315 * Instantiate a date so we can display the time zone name.
316 */
317 sdf->setTimeZone(*ttz);
318 /*
319 * Format the output.
320 */
321 UnicodeString fmtOffset;
322 FieldPosition pos(FieldPosition::DONT_CARE);
323 sdf->format(today,fmtOffset, pos);
324 // UnicodeString fmtOffset = tzS.toString();
325 UnicodeString *fmtDstOffset = 0;
326 if (fmtOffset.startsWith("GMT") && fmtOffset.length() != 3)
327 {
328 //fmtDstOffset = fmtOffset->substring(3);
329 fmtDstOffset = new UnicodeString();
330 fmtOffset.extract(3, fmtOffset.length(), *fmtDstOffset);
331 }
332 /*
333 * Show our result.
334 */
335 UBool ok = fmtDstOffset == 0 || *fmtDstOffset == dstOffset;
336 if (ok)
337 {
338 logln(UnicodeString() + i + " " + *id + " " + dstOffset +
339 " " + fmtOffset +
340 (fmtDstOffset != 0 ? " ok" : " ?"));
341 }
342 else
343 {
344 errln(UnicodeString() + i + " " + *id + " " + dstOffset +
345 " " + fmtOffset + " *** FAIL ***");
346 }
347 delete ttz;
348 delete fmtDstOffset;
349 }
350 delete cal;
351 // delete ids; // TODO: BAD API
352 delete ids;
353 delete sdf;
354 delete tz;
355 }
356
357 // -------------------------------------
358
359 /**
360 * Test operator==
361 */
362 void
TestEquals()363 DateFormatTest::TestEquals()
364 {
365 DateFormat* fmtA = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::FULL);
366 DateFormat* fmtB = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::FULL);
367 if ( fmtA == nullptr || fmtB == nullptr){
368 dataerrln("Error calling DateFormat::createDateTimeInstance");
369 delete fmtA;
370 delete fmtB;
371 return;
372 }
373
374 if (!(*fmtA == *fmtB)) errln((UnicodeString)"FAIL");
375 delete fmtA;
376 delete fmtB;
377
378 TimeZone* test = TimeZone::createTimeZone("PDT");
379 delete test;
380 }
381
382 // -------------------------------------
383
384 /**
385 * Test the parsing of 2-digit years.
386 */
387 void
TestTwoDigitYearDSTParse()388 DateFormatTest::TestTwoDigitYearDSTParse()
389 {
390 UErrorCode status = U_ZERO_ERROR;
391 SimpleDateFormat fullFmt((UnicodeString)"EEE MMM dd HH:mm:ss.SSS zzz yyyy G", status);
392 SimpleDateFormat fmt((UnicodeString)"dd-MMM-yy h:mm:ss 'o''clock' a z", Locale::getEnglish(), status);
393 //DateFormat* fmt = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::FULL, Locale::ENGLISH);
394 UnicodeString s(u"03-Apr-04 2:20:47 o'clock AM PST");
395 LocalPointer<TimeZone> defaultTZ(TimeZone::createDefault());
396 LocalPointer<TimeZone> PST(TimeZone::createTimeZone("PST"));
397 int32_t defaultOffset = defaultTZ->getRawOffset();
398 int32_t PSTOffset = PST->getRawOffset();
399 int32_t hour = 2 + (defaultOffset - PSTOffset) / (60*60*1000);
400 // hour is the expected hour of day, in units of seconds
401 hour = ((hour < 0) ? hour + 24 : hour) * 60*60;
402
403 UnicodeString str;
404
405 if(U_FAILURE(status)) {
406 dataerrln("Could not set up test. exiting - %s", u_errorName(status));
407 return;
408 }
409
410 UDate d = fmt.parse(s, status);
411 logln(s + " P> " + fullFmt.format(d, str));
412 int32_t y, m, day, hr, min, sec;
413 dateToFields(d, y, m, day, hr, min, sec);
414 hour += defaultTZ->inDaylightTime(d, status) ? 1 : 0;
415 hr = hr*60*60;
416 if (hr != hour)
417 errln((UnicodeString)"FAIL: Should parse to hour " + hour + " but got " + hr);
418
419 if (U_FAILURE(status))
420 errln((UnicodeString)"FAIL: " + (int32_t)status);
421 }
422
423 // -------------------------------------
424
toHexString(int32_t i)425 char16_t toHexString(int32_t i) { return (char16_t)(i + (i < 10 ? 0x30 : (0x41 - 10))); }
426
427 UnicodeString&
escape(UnicodeString & s)428 DateFormatTest::escape(UnicodeString& s)
429 {
430 UnicodeString buf;
431 for (int32_t i=0; i<s.length(); ++i)
432 {
433 char16_t c = s[(int32_t)i];
434 if (c <= (char16_t)0x7F) buf += c;
435 else {
436 buf += (char16_t)0x5c; buf += (char16_t)0x55;
437 buf += toHexString((c & 0xF000) >> 12);
438 buf += toHexString((c & 0x0F00) >> 8);
439 buf += toHexString((c & 0x00F0) >> 4);
440 buf += toHexString(c & 0x000F);
441 }
442 }
443 return (s = buf);
444 }
445
446 // -------------------------------------
447
448 /**
449 * This MUST be kept in sync with DateFormatSymbols.gPatternChars.
450 */
451 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
452 static const char* PATTERN_CHARS = "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB:";
453 #else
454 static const char* PATTERN_CHARS = "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB";
455 #endif
456
457 /**
458 * A list of the names of all the fields in DateFormat.
459 * This MUST be kept in sync with DateFormat.
460 */
461 static const char* DATEFORMAT_FIELD_NAMES[] = {
462 "ERA_FIELD",
463 "YEAR_FIELD",
464 "MONTH_FIELD",
465 "DATE_FIELD",
466 "HOUR_OF_DAY1_FIELD",
467 "HOUR_OF_DAY0_FIELD",
468 "MINUTE_FIELD",
469 "SECOND_FIELD",
470 "MILLISECOND_FIELD",
471 "DAY_OF_WEEK_FIELD",
472 "DAY_OF_YEAR_FIELD",
473 "DAY_OF_WEEK_IN_MONTH_FIELD",
474 "WEEK_OF_YEAR_FIELD",
475 "WEEK_OF_MONTH_FIELD",
476 "AM_PM_FIELD",
477 "HOUR1_FIELD",
478 "HOUR0_FIELD",
479 "TIMEZONE_FIELD",
480 "YEAR_WOY_FIELD",
481 "DOW_LOCAL_FIELD",
482 "EXTENDED_YEAR_FIELD",
483 "JULIAN_DAY_FIELD",
484 "MILLISECONDS_IN_DAY_FIELD",
485 "TIMEZONE_RFC_FIELD",
486 "GENERIC_TIMEZONE_FIELD",
487 "STAND_ALONE_DAY_FIELD",
488 "STAND_ALONE_MONTH_FIELD",
489 "QUARTER_FIELD",
490 "STAND_ALONE_QUARTER_FIELD",
491 "TIMEZONE_SPECIAL_FIELD",
492 "YEAR_NAME_FIELD",
493 "TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD",
494 "TIMEZONE_ISO_FIELD",
495 "TIMEZONE_ISO_LOCAL_FIELD",
496 "RELATED_YEAR_FIELD",
497 "AM_PM_MIDNIGHT_NOON_FIELD",
498 "FLEXIBLE_DAY_PERIOD_FIELD",
499 "UDAT_TIME_SEPARATOR_FIELD",
500 };
501
502 static const int32_t DATEFORMAT_FIELD_NAMES_LENGTH =
503 UPRV_LENGTHOF(DATEFORMAT_FIELD_NAMES);
504
505 /**
506 * Verify that returned field position indices are correct.
507 */
TestFieldPosition()508 void DateFormatTest::TestFieldPosition() {
509 UErrorCode ec = U_ZERO_ERROR;
510 int32_t i, j, exp;
511 UnicodeString buf;
512
513 // Verify data
514 DateFormatSymbols rootSyms(Locale(""), ec);
515 if (U_FAILURE(ec)) {
516 dataerrln("Unable to create DateFormatSymbols - %s", u_errorName(ec));
517 return;
518 }
519
520 // local pattern chars data is not longer loaded
521 // from icu locale bundle
522 assertEquals("patternChars", PATTERN_CHARS, rootSyms.getLocalPatternChars(buf));
523 assertEquals("patternChars", PATTERN_CHARS, DateFormatSymbols::getPatternUChars());
524 assertTrue("DATEFORMAT_FIELD_NAMES", DATEFORMAT_FIELD_NAMES_LENGTH == UDAT_FIELD_COUNT);
525 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
526 assertTrue("Data", UDAT_FIELD_COUNT == uprv_strlen(PATTERN_CHARS));
527 #else
528 assertTrue("Data", UDAT_FIELD_COUNT == uprv_strlen(PATTERN_CHARS) + 1); // +1 for missing TIME_SEPARATOR pattern char
529 #endif
530
531 // Create test formatters
532 const int32_t COUNT = 4;
533 DateFormat* dateFormats[COUNT];
534 dateFormats[0] = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale::getUS());
535 dateFormats[1] = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale::getFrance());
536 // Make the pattern "G y M d..."
537 buf.remove().append(PATTERN_CHARS);
538 for (j=buf.length()-1; j>=0; --j) buf.insert(j, (char16_t)32/*' '*/);
539 dateFormats[2] = new SimpleDateFormat(buf, Locale::getUS(), ec);
540 // Make the pattern "GGGG yyyy MMMM dddd..."
541 for (j=buf.length()-1; j>=0; j-=2) {
542 for (i=0; i<3; ++i) {
543 buf.insert(j, buf.charAt(j));
544 }
545 }
546 dateFormats[3] = new SimpleDateFormat(buf, Locale::getUS(), ec);
547 if(U_FAILURE(ec)){
548 errln(UnicodeString("Could not create SimpleDateFormat object for locale en_US. Error: " )+ UnicodeString(u_errorName(ec)));
549 return;
550 }
551 UDate aug13 = 871508052513.0;
552
553 // Expected output field values for above DateFormats on aug13
554 // Fields are given in order of DateFormat field number
555 const char* EXPECTED[] = {
556 "", "1997", "August", "13", "", "", "34", "12", "", "Wednesday",
557 "", "", "", "", "PM", "2", "", "Pacific Daylight Time", "", "",
558 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
559 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
560 ":",
561 #else
562 "",
563 #endif
564
565 "", "1997", "ao\\u00FBt", "13", "", "14", "34", "12", "", "mercredi",
566 "", "", "", "", "", "", "", "heure d\\u2019\\u00E9t\\u00E9 du Pacifique nord-am\\u00E9ricain", "", "",
567 "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
568 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
569 ":",
570 #else
571 "",
572 #endif
573
574 "AD", "1997", "8", "13", "14", "14", "34", "12", "5", "Wed",
575 "225", "2", "33", "3", "PM", "2", "2", "PDT", "1997", "4",
576 "1997", "2450674", "52452513", "-0700", "PT", "4", "8", "3", "3", "uslax",
577 "1997", "GMT-7", "-07", "-07", "1997", "PM", "in the afternoon",
578 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
579 ":",
580 #else
581 "",
582 #endif
583
584 "Anno Domini", "1997", "August", "0013", "0014", "0014", "0034", "0012", "5130", "Wednesday",
585 "0225", "0002", "0033", "0003", "PM", "0002", "0002", "Pacific Daylight Time", "1997", "Wednesday",
586 "1997", "2450674", "52452513", "GMT-07:00", "Pacific Time", "Wednesday", "August", "3rd quarter", "3rd quarter", "Los Angeles Time",
587 "1997", "GMT-07:00", "-0700", "-0700", "1997", "PM", "in the afternoon",
588 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
589 ":",
590 #else
591 "",
592 #endif
593 };
594
595 const int32_t EXPECTED_LENGTH = UPRV_LENGTHOF(EXPECTED);
596
597 assertTrue("data size", EXPECTED_LENGTH == COUNT * UDAT_FIELD_COUNT);
598
599 TimeZone* PT = TimeZone::createTimeZone("America/Los_Angeles");
600 for (j = 0, exp = 0; j < COUNT; ++j) {
601 // String str;
602 DateFormat* df = dateFormats[j];
603 df->setTimeZone(*PT);
604 SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(df);
605 if (sdtfmt != nullptr) {
606 logln(" Pattern = " + sdtfmt->toPattern(buf.remove()));
607 } else {
608 logln(" Pattern = ? (not a SimpleDateFormat)");
609 }
610 logln((UnicodeString)" Result = " + df->format(aug13, buf.remove()));
611
612 int32_t expBase = exp; // save for later
613 for (i = 0; i < UDAT_FIELD_COUNT; ++i, ++exp) {
614 FieldPosition pos(i);
615 buf.remove();
616 df->format(aug13, buf, pos);
617 UnicodeString field;
618 buf.extractBetween(pos.getBeginIndex(), pos.getEndIndex(), field);
619 assertEquals((UnicodeString)"localeidx #" + j + " field #" + i + " " +
620 DATEFORMAT_FIELD_NAMES[i], ctou(EXPECTED[exp]), field);
621 }
622
623 // test FieldPositionIterator API
624 logln("FieldPositionIterator");
625 {
626 UErrorCode status = U_ZERO_ERROR;
627 FieldPositionIterator posIter;
628 FieldPosition fp;
629
630 buf.remove();
631 df->format(aug13, buf, &posIter, status);
632 while (posIter.next(fp)) {
633 int32_t i = fp.getField();
634 UnicodeString field;
635 buf.extractBetween(fp.getBeginIndex(), fp.getEndIndex(), field);
636 assertEquals((UnicodeString)"localeidx #" + j + " field #" + i + " " +
637 DATEFORMAT_FIELD_NAMES[i], ctou(EXPECTED[expBase + i]), field);
638 }
639
640 }
641 }
642
643
644 // test null posIter
645 buf.remove();
646 UErrorCode status = U_ZERO_ERROR;
647 dateFormats[0]->format(aug13, buf, nullptr, status);
648 // if we didn't crash, we succeeded.
649
650 for (i=0; i<COUNT; ++i) {
651 delete dateFormats[i];
652 }
653 delete PT;
654 }
655
656 // -------------------------------------
657
658 /**
659 * General parse/format tests. Add test cases as needed.
660 */
TestGeneral()661 void DateFormatTest::TestGeneral() {
662 const char* DATA[] = {
663 "yyyy MM dd HH:mm:ss.SSS",
664
665 // Milliseconds are left-justified, since they format as fractions of a second
666 "y/M/d H:mm:ss.S", "fp", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.5", "2004 03 10 16:36:31.500",
667 "y/M/d H:mm:ss.SS", "fp", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.56", "2004 03 10 16:36:31.560",
668 "y/M/d H:mm:ss.SSS", "F", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.567",
669 "y/M/d H:mm:ss.SSSS", "pf", "2004/3/10 16:36:31.5679", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.5670",
670 };
671 expect(DATA, UPRV_LENGTHOF(DATA), Locale("en", "", ""));
672 }
673
674 // -------------------------------------
675
676 /**
677 * Verify that strings which contain incomplete specifications are parsed
678 * correctly. In some instances, this means not being parsed at all, and
679 * returning an appropriate error.
680 */
681 void
TestPartialParse994()682 DateFormatTest::TestPartialParse994()
683 {
684 UErrorCode status = U_ZERO_ERROR;
685 SimpleDateFormat* f = new SimpleDateFormat(status);
686 if (U_FAILURE(status)) {
687 dataerrln("Fail new SimpleDateFormat: %s", u_errorName(status));
688 delete f;
689 return;
690 }
691 UDate null = 0;
692 tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10:11:42", date(97, 1 - 1, 17, 10, 11, 42));
693 tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10:", null);
694 tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 10", null);
695 tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17 ", null);
696 tryPat994(f, "yy/MM/dd HH:mm:ss", "97/01/17", null);
697 if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
698 delete f;
699 }
700
701 // -------------------------------------
702
703 void
tryPat994(SimpleDateFormat * format,const char * pat,const char * str,UDate expected)704 DateFormatTest::tryPat994(SimpleDateFormat* format, const char* pat, const char* str, UDate expected)
705 {
706 UErrorCode status = U_ZERO_ERROR;
707 UDate null = 0;
708 logln(UnicodeString("Pattern \"") + pat + "\" String \"" + str + "\"");
709 //try {
710 format->applyPattern(pat);
711 UDate date = format->parse(str, status);
712 if (U_FAILURE(status) || date == null)
713 {
714 logln((UnicodeString)"ParseException: " + (int32_t)status);
715 if (expected != null) errln((UnicodeString)"FAIL: Expected " + dateToString(expected));
716 }
717 else
718 {
719 UnicodeString f;
720 (dynamic_cast<DateFormat*>(format))->format(date, f);
721 logln(UnicodeString(" parse(") + str + ") -> " + dateToString(date));
722 logln((UnicodeString)" format -> " + f);
723 if (expected == null ||
724 !(date == expected)) errln((UnicodeString)"FAIL: Expected null");//" + expected);
725 if (!(f == str)) errln(UnicodeString("FAIL: Expected ") + str);
726 }
727 //}
728 //catch(ParseException e) {
729 // logln((UnicodeString)"ParseException: " + e.getMessage());
730 // if (expected != null) errln((UnicodeString)"FAIL: Expected " + dateToString(expected));
731 //}
732 //catch(Exception e) {
733 // errln((UnicodeString)"*** Exception:");
734 // e.printStackTrace();
735 //}
736 }
737
738 // -------------------------------------
739
740 /**
741 * Verify the behavior of patterns in which digits for different fields run together
742 * without intervening separators.
743 */
744 void
TestRunTogetherPattern985()745 DateFormatTest::TestRunTogetherPattern985()
746 {
747 UErrorCode status = U_ZERO_ERROR;
748 UnicodeString format("yyyyMMddHHmmssSSS");
749 UnicodeString now, then;
750 //UBool flag;
751 SimpleDateFormat *formatter = new SimpleDateFormat(format, status);
752 if (U_FAILURE(status)) {
753 dataerrln("Fail new SimpleDateFormat: %s", u_errorName(status));
754 delete formatter;
755 return;
756 }
757 UDate date1 = Calendar::getNow();
758 (dynamic_cast<DateFormat*>(formatter))->format(date1, now);
759 logln(now);
760 ParsePosition pos(0);
761 UDate date2 = formatter->parse(now, pos);
762 if (date2 == 0) then = UnicodeString("Parse stopped at ") + pos.getIndex();
763 else (dynamic_cast<DateFormat*>(formatter))->format(date2, then);
764 logln(then);
765 if (!(date2 == date1)) errln((UnicodeString)"FAIL");
766 delete formatter;
767 if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
768 }
769
770 // -------------------------------------
771
772 /**
773 * Verify the behavior of patterns in which digits for different fields run together
774 * without intervening separators.
775 */
776 void
TestRunTogetherPattern917()777 DateFormatTest::TestRunTogetherPattern917()
778 {
779 UErrorCode status = U_ZERO_ERROR;
780 SimpleDateFormat* fmt;
781 UnicodeString myDate;
782 fmt = new SimpleDateFormat((UnicodeString)"yyyy/MM/dd", status);
783 if (U_FAILURE(status)) {
784 dataerrln("Fail new SimpleDateFormat: %s", u_errorName(status));
785 delete fmt;
786 return;
787 }
788 myDate = "1997/02/03";
789 testIt917(fmt, myDate, date(97, 2 - 1, 3));
790 delete fmt;
791 fmt = new SimpleDateFormat((UnicodeString)"yyyyMMdd", status);
792 myDate = "19970304";
793 testIt917(fmt, myDate, date(97, 3 - 1, 4));
794 delete fmt;
795 if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
796 }
797
798 // -------------------------------------
799
800 void
testIt917(SimpleDateFormat * fmt,UnicodeString & str,UDate expected)801 DateFormatTest::testIt917(SimpleDateFormat* fmt, UnicodeString& str, UDate expected)
802 {
803 UErrorCode status = U_ZERO_ERROR;
804 UnicodeString pattern;
805 logln((UnicodeString)"pattern=" + fmt->toPattern(pattern) + " string=" + str);
806 Formattable o;
807 //try {
808 dynamic_cast<Format*>(fmt)->parseObject(str, o, status);
809 //}
810 if (U_FAILURE(status)) return;
811 //catch(ParseException e) {
812 // e.printStackTrace();
813 // return;
814 //}
815 logln((UnicodeString)"Parsed object: " + dateToString(o.getDate()));
816 if (!(o.getDate() == expected)) errln((UnicodeString)"FAIL: Expected " + dateToString(expected));
817 UnicodeString formatted;
818 fmt->format(o, formatted, status);
819 logln((UnicodeString)"Formatted string: " + formatted);
820 if (!(formatted == str)) errln((UnicodeString)"FAIL: Expected " + str);
821 if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
822 }
823
824 // -------------------------------------
825
826 /**
827 * Verify the handling of Czech June and July, which have the unique attribute that
828 * one is a proper prefix substring of the other.
829 */
830 void
TestCzechMonths459()831 DateFormatTest::TestCzechMonths459()
832 {
833 UErrorCode status = U_ZERO_ERROR;
834 DateFormat* fmt = DateFormat::createDateInstance(DateFormat::FULL, Locale("cs", "", ""));
835 if (fmt == nullptr){
836 dataerrln("Error calling DateFormat::createDateInstance()");
837 return;
838 }
839
840 UnicodeString pattern;
841 logln((UnicodeString)"Pattern " + (dynamic_cast<SimpleDateFormat*>(fmt))->toPattern(pattern));
842 UDate june = date(97, UCAL_JUNE, 15);
843 UDate july = date(97, UCAL_JULY, 15);
844 UnicodeString juneStr; fmt->format(june, juneStr);
845 UnicodeString julyStr; fmt->format(july, julyStr);
846 //try {
847 logln((UnicodeString)"format(June 15 1997) = " + juneStr);
848 UDate d = fmt->parse(juneStr, status);
849 UnicodeString s; fmt->format(d, s);
850 int32_t month,yr,day,hr,min,sec; dateToFields(d,yr,month,day,hr,min,sec);
851 logln((UnicodeString)" -> parse -> " + s + " (month = " + month + ")");
852 if (month != UCAL_JUNE) errln((UnicodeString)"FAIL: Month should be June");
853 logln((UnicodeString)"format(July 15 1997) = " + julyStr);
854 d = fmt->parse(julyStr, status);
855 fmt->format(d, s);
856 dateToFields(d,yr,month,day,hr,min,sec);
857 logln((UnicodeString)" -> parse -> " + s + " (month = " + month + ")");
858 if (month != UCAL_JULY) errln((UnicodeString)"FAIL: Month should be July");
859 //}
860 //catch(ParseException e) {
861 if (U_FAILURE(status))
862 errln((UnicodeString)"Exception: " + (int32_t)status);
863 //}
864 delete fmt;
865 }
866
867 // -------------------------------------
868
869 /**
870 * Test the handling of 'D' in patterns.
871 */
872 void
TestLetterDPattern212()873 DateFormatTest::TestLetterDPattern212()
874 {
875 UErrorCode status = U_ZERO_ERROR;
876 UnicodeString dateString("1995-040.05:01:29");
877 UnicodeString bigD("yyyy-DDD.hh:mm:ss");
878 UnicodeString littleD("yyyy-ddd.hh:mm:ss");
879 UDate expLittleD = date(95, 0, 1, 5, 1, 29);
880 UDate expBigD = expLittleD + 39 * 24 * 3600000.0;
881 expLittleD = expBigD; // Expect the same, with default lenient parsing
882 logln((UnicodeString)"dateString= " + dateString);
883 SimpleDateFormat *formatter = new SimpleDateFormat(bigD, status);
884 if (U_FAILURE(status)) {
885 dataerrln("Fail new SimpleDateFormat: %s", u_errorName(status));
886 delete formatter;
887 return;
888 }
889 ParsePosition pos(0);
890 UDate myDate = formatter->parse(dateString, pos);
891 logln((UnicodeString)"Using " + bigD + " -> " + myDate);
892 if (myDate != expBigD) errln((UnicodeString)"FAIL: bigD - Expected " + dateToString(expBigD));
893 delete formatter;
894 formatter = new SimpleDateFormat(littleD, status);
895 ASSERT_OK(status);
896 pos = ParsePosition(0);
897 myDate = formatter->parse(dateString, pos);
898 logln((UnicodeString)"Using " + littleD + " -> " + dateToString(myDate));
899 if (myDate != expLittleD) errln((UnicodeString)"FAIL: littleD - Expected " + dateToString(expLittleD));
900 delete formatter;
901 if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
902 }
903
904 // -------------------------------------
905
906 /**
907 * Test the day of year pattern.
908 */
909 void
TestDayOfYearPattern195()910 DateFormatTest::TestDayOfYearPattern195()
911 {
912 UErrorCode status = U_ZERO_ERROR;
913 UDate today = Calendar::getNow();
914 int32_t year,month,day,hour,min,sec; dateToFields(today,year,month,day,hour,min,sec);
915 UDate expected = date(year, month, day);
916 logln((UnicodeString)"Test Date: " + dateToString(today));
917 SimpleDateFormat* sdf = dynamic_cast<SimpleDateFormat*>(DateFormat::createDateInstance());
918 if (sdf == nullptr){
919 dataerrln("Error calling DateFormat::createDateInstance()");
920 return;
921 }
922 tryPattern(*sdf, today, 0, expected);
923 tryPattern(*sdf, today, "G yyyy DDD", expected);
924 delete sdf;
925 if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
926 }
927
928 // -------------------------------------
929
930 void
tryPattern(SimpleDateFormat & sdf,UDate d,const char * pattern,UDate expected)931 DateFormatTest::tryPattern(SimpleDateFormat& sdf, UDate d, const char* pattern, UDate expected)
932 {
933 UErrorCode status = U_ZERO_ERROR;
934 if (pattern != 0) sdf.applyPattern(pattern);
935 UnicodeString thePat;
936 logln((UnicodeString)"pattern: " + sdf.toPattern(thePat));
937 UnicodeString formatResult; (*dynamic_cast<DateFormat*>(&sdf)).format(d, formatResult);
938 logln((UnicodeString)" format -> " + formatResult);
939 // try {
940 UDate d2 = sdf.parse(formatResult, status);
941 logln((UnicodeString)" parse(" + formatResult + ") -> " + dateToString(d2));
942 if (d2 != expected) errln((UnicodeString)"FAIL: Expected " + dateToString(expected));
943 UnicodeString format2; (*dynamic_cast<DateFormat*>(&sdf)).format(d2, format2);
944 logln((UnicodeString)" format -> " + format2);
945 if (!(formatResult == format2)) errln((UnicodeString)"FAIL: Round trip drift");
946 //}
947 //catch(Exception e) {
948 if (U_FAILURE(status))
949 errln((UnicodeString)"Error: " + (int32_t)status);
950 //}
951 }
952
953 // -------------------------------------
954
955 /**
956 * Test the handling of single quotes in patterns.
957 */
958 void
TestQuotePattern161()959 DateFormatTest::TestQuotePattern161()
960 {
961 UErrorCode status = U_ZERO_ERROR;
962 SimpleDateFormat* formatter = new SimpleDateFormat((UnicodeString)"MM/dd/yyyy 'at' hh:mm:ss a zzz", status);
963 if (U_FAILURE(status)) {
964 dataerrln("Fail new SimpleDateFormat: %s", u_errorName(status));
965 delete formatter;
966 return;
967 }
968 UDate currentTime_1 = date(97, UCAL_AUGUST, 13, 10, 42, 28);
969 UnicodeString dateString; (dynamic_cast<DateFormat*>(formatter))->format(currentTime_1, dateString);
970 UnicodeString exp("08/13/1997 at 10:42:28 AM ");
971 logln((UnicodeString)"format(" + dateToString(currentTime_1) + ") = " + dateString);
972 if (0 != dateString.compareBetween(0, exp.length(), exp, 0, exp.length())) errln((UnicodeString)"FAIL: Expected " + exp);
973 delete formatter;
974 if (U_FAILURE(status)) errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
975 }
976
977 // -------------------------------------
978
979 /**
980 * Verify the correct behavior when handling invalid input strings.
981 */
982 void
TestBadInput135()983 DateFormatTest::TestBadInput135()
984 {
985 UErrorCode status = U_ZERO_ERROR;
986 DateFormat::EStyle looks[] = {
987 DateFormat::SHORT, DateFormat::MEDIUM, DateFormat::LONG, DateFormat::FULL
988 };
989 int32_t looks_length = UPRV_LENGTHOF(looks);
990 const char* strings[] = {
991 "Mar 15", "Mar 15 1997", "asdf", "3/1/97 1:23:", "3/1/00 1:23:45 AM"
992 };
993 int32_t strings_length = UPRV_LENGTHOF(strings);
994 DateFormat *longFmt = DateFormat::createDateTimeInstance(DateFormat::LONG, DateFormat::MEDIUM, Locale::getEnglish());
995 if(longFmt==nullptr) {
996 dataerrln("could not create date time instance");
997 return;
998 }
999 UnicodeString expected(u"March 1, 2000 at 1:23:45\u202FAM", -1);
1000 for (int32_t i = 0; i < strings_length;++i) {
1001 const char* text = strings[i];
1002 for (int32_t j = 0; j < looks_length;++j) {
1003 DateFormat::EStyle dateLook = looks[j];
1004 for (int32_t k = 0; k < looks_length;++k) {
1005 DateFormat::EStyle timeLook = looks[k];
1006 DateFormat *df = DateFormat::createDateTimeInstance(dateLook, timeLook);
1007 if (df == nullptr){
1008 dataerrln("Error calling DateFormat::createDateTimeInstance()");
1009 continue;
1010 }
1011 UnicodeString prefix = UnicodeString(text) + ", " + dateLook + "/" + timeLook + ": ";
1012 //try {
1013 UDate when = df->parse(text, status);
1014 if (when == 0 && U_SUCCESS(status)) {
1015 errln(prefix + "SHOULD NOT HAPPEN: parse returned 0.");
1016 continue;
1017 }
1018 if (U_SUCCESS(status))
1019 {
1020 UnicodeString format;
1021 UnicodeString pattern;
1022 SimpleDateFormat* sdtfmt = dynamic_cast<SimpleDateFormat*>(df);
1023 if (sdtfmt != nullptr) {
1024 sdtfmt->toPattern(pattern);
1025 }
1026 longFmt->format(when, format);
1027 logln(prefix + "OK: " + format);
1028 if (0!=format.compareBetween(0, expected.length(), expected, 0, expected.length()))
1029 errln((UnicodeString)"FAIL: Parse \"" + text + "\", pattern \"" + pattern + "\", expected " + expected + " got " + format);
1030 }
1031 //}
1032 //catch(ParseException e) {
1033 else
1034 status = U_ZERO_ERROR;
1035 //}
1036 //catch(StringIndexOutOfBoundsException e) {
1037 // errln(prefix + "SHOULD NOT HAPPEN: " + (int)status);
1038 //}
1039 delete df;
1040 }
1041 }
1042 }
1043 delete longFmt;
1044 if (U_FAILURE(status))
1045 errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
1046 }
1047
1048 static const char* const parseFormats[] = {
1049 "MMMM d, yyyy",
1050 "MMMM d yyyy",
1051 "M/d/yy",
1052 "d MMMM, yyyy",
1053 "d MMMM yyyy",
1054 "d MMMM",
1055 "MMMM d",
1056 "yyyy",
1057 "h:mm a MMMM d, yyyy"
1058 };
1059
1060 #if 0
1061 // strict inputStrings
1062 static const char* const inputStrings[] = {
1063 "bogus string", 0, 0, 0, 0, 0, 0, 0, 0, 0,
1064 "April 1, 1997", "April 1, 1997", 0, 0, 0, 0, 0, "April 1", 0, 0,
1065 "Jan 1, 1970", "January 1, 1970", 0, 0, 0, 0, 0, "January 1", 0, 0,
1066 "Jan 1 2037", 0, "January 1 2037", 0, 0, 0, 0, "January 1", 0, 0,
1067 "1/1/70", 0, 0, "1/1/70", 0, 0, 0, 0, "0001", 0,
1068 "5 May 1997", 0, 0, 0, 0, "5 May 1997", "5 May", 0, "0005", 0,
1069 "16 May", 0, 0, 0, 0, 0, "16 May", 0, "0016", 0,
1070 "April 30", 0, 0, 0, 0, 0, 0, "April 30", 0, 0,
1071 "1998", 0, 0, 0, 0, 0, 0, 0, "1998", 0,
1072 "1", 0, 0, 0, 0, 0, 0, 0, "0001", 0,
1073 "3:00 pm Jan 1, 1997", 0, 0, 0, 0, 0, 0, 0, "0003", "3:00 PM January 1, 1997",
1074 };
1075 #else
1076 // lenient inputStrings
1077 static const char* const inputStrings[] = {
1078 "bogus string", 0, 0, 0, 0, 0, 0, 0, 0, 0,
1079 "April 1, 1997", "April 1, 1997", "April 1 1997", "4/1/97", 0, 0, 0, "April 1", 0, 0,
1080 "Jan 1, 1970", "January 1, 1970", "January 1 1970", "1/1/70", 0, 0, 0, "January 1", 0, 0,
1081 "Jan 1 2037", "January 1, 2037", "January 1 2037", "1/1/37", 0, 0, 0, "January 1", 0, 0,
1082 "1/1/70", "January 1, 0070", "January 1 0070", "1/1/70", "1 January, 0070", "1 January 0070", "1 January", "January 1", "0001", 0,
1083 "5 May 1997", 0, 0, 0, "5 May, 1997", "5 May 1997", "5 May", 0, "0005", 0,
1084 "16 May", 0, 0, 0, 0, 0, "16 May", 0, "0016", 0,
1085 "April 30", 0, 0, 0, 0, 0, 0, "April 30", 0, 0,
1086 "1998", 0, 0, 0, 0, 0, 0, 0, "1998", 0,
1087 "1", 0, 0, 0, 0, 0, 0, 0, "0001", 0,
1088 "3:00 pm Jan 1, 1997", 0, 0, 0, 0, 0, 0, 0, "0003", "3:00 PM January 1, 1997",
1089 };
1090 #endif
1091
1092 // -------------------------------------
1093
1094 /**
1095 * Verify the correct behavior when parsing an array of inputs against an
1096 * array of patterns, with known results. The results are encoded after
1097 * the input strings in each row.
1098 */
1099 void
TestBadInput135a()1100 DateFormatTest::TestBadInput135a()
1101 {
1102 UErrorCode status = U_ZERO_ERROR;
1103 SimpleDateFormat* dateParse = new SimpleDateFormat(status);
1104 if(U_FAILURE(status)) {
1105 dataerrln("Failed creating SimpleDateFormat with %s. Quitting test", u_errorName(status));
1106 delete dateParse;
1107 return;
1108 }
1109 const char* s;
1110 UDate date;
1111 const uint32_t PF_LENGTH = UPRV_LENGTHOF(parseFormats);
1112 const uint32_t INPUT_LENGTH = UPRV_LENGTHOF(inputStrings);
1113
1114 dateParse->applyPattern("d MMMM, yyyy");
1115 dateParse->adoptTimeZone(TimeZone::createDefault());
1116 s = "not parseable";
1117 UnicodeString thePat;
1118 logln(UnicodeString("Trying to parse \"") + s + "\" with " + dateParse->toPattern(thePat));
1119 //try {
1120 date = dateParse->parse(s, status);
1121 if (U_SUCCESS(status))
1122 errln((UnicodeString)"FAIL: Expected exception during parse");
1123 //}
1124 //catch(Exception ex) {
1125 else
1126 logln((UnicodeString)"Exception during parse: " + (int32_t)status);
1127 status = U_ZERO_ERROR;
1128 //}
1129 for (uint32_t i = 0; i < INPUT_LENGTH; i += (PF_LENGTH + 1)) {
1130 ParsePosition parsePosition(0);
1131 UnicodeString s( inputStrings[i]);
1132 for (uint32_t index = 0; index < PF_LENGTH;++index) {
1133 const char* expected = inputStrings[i + 1 + index];
1134 dateParse->applyPattern(parseFormats[index]);
1135 dateParse->adoptTimeZone(TimeZone::createDefault());
1136 //try {
1137 parsePosition.setIndex(0);
1138 date = dateParse->parse(s, parsePosition);
1139 if (parsePosition.getIndex() != 0) {
1140 UnicodeString s1, s2;
1141 s.extract(0, parsePosition.getIndex(), s1);
1142 s.extract(parsePosition.getIndex(), s.length(), s2);
1143 if (date == 0) {
1144 errln((UnicodeString)"ERROR: null result fmt=\"" +
1145 parseFormats[index] +
1146 "\" pos=" + parsePosition.getIndex() + " " +
1147 s1 + "|" + s2);
1148 }
1149 else {
1150 UnicodeString result;
1151 (dynamic_cast<DateFormat*>(dateParse))->format(date, result);
1152 logln((UnicodeString)"Parsed \"" + s + "\" using \"" + dateParse->toPattern(thePat) + "\" to: " + result);
1153 if (expected == 0)
1154 errln((UnicodeString)"FAIL: Expected parse failure, got " + result);
1155 else if (!(result == expected))
1156 errln(UnicodeString("FAIL: Parse \"") + s + UnicodeString("\", expected ") + expected + UnicodeString(", got ") + result);
1157 }
1158 }
1159 else if (expected != 0) {
1160 errln(UnicodeString("FAIL: Expected ") + expected + " from \"" +
1161 s + "\" with \"" + dateParse->toPattern(thePat) + "\"");
1162 }
1163 //}
1164 //catch(Exception ex) {
1165 if (U_FAILURE(status))
1166 errln((UnicodeString)"An exception was thrown during parse: " + (int32_t)status);
1167 //}
1168 }
1169 }
1170 delete dateParse;
1171 if (U_FAILURE(status))
1172 errln((UnicodeString)"FAIL: UErrorCode received during test: " + (int32_t)status);
1173 }
1174
1175 // -------------------------------------
1176
1177 /**
1178 * Test the parsing of two-digit years.
1179 */
1180 void
TestTwoDigitYear()1181 DateFormatTest::TestTwoDigitYear()
1182 {
1183 UErrorCode ec = U_ZERO_ERROR;
1184 SimpleDateFormat fmt("dd/MM/yy", Locale::getUK(), ec);
1185 if (U_FAILURE(ec)) {
1186 dataerrln("FAIL: SimpleDateFormat constructor - %s", u_errorName(ec));
1187 return;
1188 }
1189 parse2DigitYear(fmt, "5/6/30", date(130, UCAL_JUNE, 5));
1190 parse2DigitYear(fmt, "4/6/50", date(50, UCAL_JUNE, 4));
1191 }
1192
1193 // -------------------------------------
1194
1195 void
parse2DigitYear(DateFormat & fmt,const char * str,UDate expected)1196 DateFormatTest::parse2DigitYear(DateFormat& fmt, const char* str, UDate expected)
1197 {
1198 UErrorCode status = U_ZERO_ERROR;
1199 //try {
1200 UDate d = fmt.parse(str, status);
1201 UnicodeString thePat;
1202 logln(UnicodeString("Parsing \"") + str + "\" with " + (dynamic_cast<SimpleDateFormat*>(&fmt))->toPattern(thePat) +
1203 " => " + dateToString(d));
1204 if (d != expected) errln((UnicodeString)"FAIL: Expected " + expected);
1205 //}
1206 //catch(ParseException e) {
1207 if (U_FAILURE(status))
1208 errln((UnicodeString)"FAIL: Got exception");
1209 //}
1210 }
1211
1212 // -------------------------------------
1213
1214 /**
1215 * Test the formatting of time zones.
1216 */
1217 void
TestDateFormatZone061()1218 DateFormatTest::TestDateFormatZone061()
1219 {
1220 UErrorCode status = U_ZERO_ERROR;
1221 UDate date;
1222 DateFormat *formatter;
1223 date= 859248000000.0;
1224 logln((UnicodeString)"Date 1997/3/25 00:00 GMT: " + date);
1225 formatter = new SimpleDateFormat((UnicodeString)"dd-MMM-yyyyy HH:mm", Locale::getUK(), status);
1226 if(U_FAILURE(status)) {
1227 dataerrln("Failed creating SimpleDateFormat with %s. Quitting test", u_errorName(status));
1228 delete formatter;
1229 return;
1230 }
1231 formatter->adoptTimeZone(TimeZone::createTimeZone("GMT"));
1232 UnicodeString temp; formatter->format(date, temp);
1233 logln((UnicodeString)"Formatted in GMT to: " + temp);
1234 //try {
1235 UDate tempDate = formatter->parse(temp, status);
1236 logln((UnicodeString)"Parsed to: " + dateToString(tempDate));
1237 if (tempDate != date) errln((UnicodeString)"FAIL: Expected " + dateToString(date));
1238 //}
1239 //catch(Throwable t) {
1240 if (U_FAILURE(status))
1241 errln((UnicodeString)"Date Formatter throws: " + (int32_t)status);
1242 //}
1243 delete formatter;
1244 }
1245
1246 // -------------------------------------
1247
1248 /**
1249 * Test the formatting of time zones.
1250 */
1251 void
TestDateFormatZone146()1252 DateFormatTest::TestDateFormatZone146()
1253 {
1254 TimeZone *saveDefault = TimeZone::createDefault();
1255
1256 //try {
1257 TimeZone *thedefault = TimeZone::createTimeZone("GMT");
1258 TimeZone::setDefault(*thedefault);
1259 // java.util.Locale.setDefault(new java.util.Locale("ar", "", ""));
1260
1261 // check to be sure... its GMT all right
1262 TimeZone *testdefault = TimeZone::createDefault();
1263 UnicodeString testtimezone;
1264 testdefault->getID(testtimezone);
1265 if (testtimezone == "GMT")
1266 logln("Test timezone = " + testtimezone);
1267 else
1268 dataerrln("Test timezone should be GMT, not " + testtimezone);
1269
1270 UErrorCode status = U_ZERO_ERROR;
1271 // now try to use the default GMT time zone
1272 GregorianCalendar *greenwichcalendar =
1273 new GregorianCalendar(1997, 3, 4, 23, 0, status);
1274 if (U_FAILURE(status)) {
1275 dataerrln("Fail new GregorianCalendar: %s", u_errorName(status));
1276 } else {
1277 //*****************************greenwichcalendar.setTimeZone(TimeZone.getDefault());
1278 //greenwichcalendar.set(1997, 3, 4, 23, 0);
1279 // try anything to set hour to 23:00 !!!
1280 greenwichcalendar->set(UCAL_HOUR_OF_DAY, 23);
1281 // get time
1282 UDate greenwichdate = greenwichcalendar->getTime(status);
1283 // format every way
1284 UnicodeString DATA [] = {
1285 UnicodeString("simple format: "), UnicodeString("04/04/97 23:00 GMT"),
1286 UnicodeString("MM/dd/yy HH:mm z"),
1287 UnicodeString("full format: "), UnicodeString("Friday, April 4, 1997 11:00:00 o'clock PM GMT"),
1288 UnicodeString("EEEE, MMMM d, yyyy h:mm:ss 'o''clock' a z"),
1289 UnicodeString("long format: "), UnicodeString("April 4, 1997 11:00:00 PM GMT"),
1290 UnicodeString("MMMM d, yyyy h:mm:ss a z"),
1291 UnicodeString("default format: "), UnicodeString("04-Apr-97 11:00:00 PM"),
1292 UnicodeString("dd-MMM-yy h:mm:ss a"),
1293 UnicodeString("short format: "), UnicodeString("4/4/97 11:00 PM"),
1294 UnicodeString("M/d/yy h:mm a")
1295 };
1296 int32_t DATA_length = UPRV_LENGTHOF(DATA);
1297
1298 for (int32_t i=0; i<DATA_length; i+=3) {
1299 SimpleDateFormat fmt(DATA[i+2], Locale::getEnglish(), status);
1300 if (U_FAILURE(status)) {
1301 dataerrln("Unable to create SimpleDateFormat - %s", u_errorName(status));
1302 break;
1303 }
1304 fmt.setCalendar(*greenwichcalendar);
1305 UnicodeString result;
1306 result = fmt.format(greenwichdate, result);
1307 logln(DATA[i] + result);
1308 if (result != DATA[i+1])
1309 errln("FAIL: Expected " + DATA[i+1] + ", got " + result);
1310 }
1311 }
1312 //}
1313 //finally {
1314 TimeZone::adoptDefault(saveDefault);
1315 //}
1316 delete testdefault;
1317 delete greenwichcalendar;
1318 delete thedefault;
1319
1320
1321 }
1322
1323 // -------------------------------------
1324
1325 /**
1326 * Test the formatting of dates in different locales.
1327 */
1328 void
TestLocaleDateFormat()1329 DateFormatTest::TestLocaleDateFormat() // Bug 495
1330 {
1331 UDate testDate = date(97, UCAL_SEPTEMBER, 15);
1332 DateFormat *dfFrench = DateFormat::createDateTimeInstance(DateFormat::FULL,
1333 DateFormat::FULL, Locale::getFrench());
1334 DateFormat *dfUS = DateFormat::createDateTimeInstance(DateFormat::FULL,
1335 DateFormat::FULL, Locale::getUS());
1336 UnicodeString expectedFRENCH ( u"lundi 15 septembre 1997 à 00:00:00 heure d’été du Pacifique nord-américain", -1 );
1337 expectedFRENCH = expectedFRENCH.unescape();
1338 UnicodeString expectedUS ( u"Monday, September 15, 1997 at 12:00:00\u202FAM Pacific Daylight Time", -1 );
1339 logln((UnicodeString)"Date set to : " + dateToString(testDate));
1340 UnicodeString out;
1341 if (dfUS == nullptr || dfFrench == nullptr){
1342 dataerrln("Error calling DateFormat::createDateTimeInstance)");
1343 delete dfUS;
1344 delete dfFrench;
1345 return;
1346 }
1347
1348 dfFrench->format(testDate, out);
1349 logln((UnicodeString)"Date Formatted with French Locale " + out);
1350 if (!(out == expectedFRENCH))
1351 errln((UnicodeString)"FAIL: Expected " + expectedFRENCH + ", got " + out);
1352 out.truncate(0);
1353 dfUS->format(testDate, out);
1354 logln((UnicodeString)"Date Formatted with US Locale " + out);
1355 if (!(out == expectedUS))
1356 errln((UnicodeString)"FAIL: Expected " + expectedUS + ", got " + out);
1357 delete dfUS;
1358 delete dfFrench;
1359 }
1360
1361 void
TestFormattingLocaleTimeSeparator()1362 DateFormatTest::TestFormattingLocaleTimeSeparator()
1363 {
1364 // This test not as useful as it once was, since timeSeparator
1365 // in the Arabic locale is changed back to ":" in CLDR 28.
1366 const UDate testDate = 874266720000.; // Sun Sep 14 21:52:00 CET 1997
1367 logln((UnicodeString)"Date set to : " + dateToString(testDate));
1368
1369 const LocalPointer<const TimeZone> tz(TimeZone::createTimeZone("CET"));
1370
1371 const LocalPointer<DateFormat> dfArab(DateFormat::createTimeInstance(
1372 DateFormat::SHORT, Locale("ar", "EG")));
1373
1374 const LocalPointer<DateFormat> dfLatn(DateFormat::createTimeInstance(
1375 DateFormat::SHORT, Locale("ar", "EG", nullptr, "numbers=latn")));
1376
1377 if (dfLatn.isNull() || dfArab.isNull()) {
1378 dataerrln("Error calling DateFormat::createTimeInstance()");
1379 return;
1380 }
1381
1382 dfArab->setTimeZone(*tz);
1383 dfLatn->setTimeZone(*tz);
1384
1385 const UnicodeString expectedArab = UnicodeString(
1386 "\\u0669:\\u0665\\u0662 \\u0645", -1, US_INV).unescape();
1387
1388 const UnicodeString expectedLatn = UnicodeString(
1389 "9:52 \\u0645", -1, US_INV).unescape();
1390
1391 UnicodeString actualArab;
1392 UnicodeString actualLatn;
1393
1394 dfArab->format(testDate, actualArab);
1395 dfLatn->format(testDate, actualLatn);
1396
1397 assertEquals("Arab", expectedArab, actualArab);
1398 assertEquals("Latn", expectedLatn, actualLatn);
1399 }
1400
1401 /**
1402 * Test DateFormat(Calendar) API
1403 */
TestDateFormatCalendar()1404 void DateFormatTest::TestDateFormatCalendar() {
1405 DateFormat *date=0, *time=0, *full=0;
1406 Calendar *cal=0;
1407 UnicodeString str;
1408 ParsePosition pos;
1409 UDate when;
1410 UErrorCode ec = U_ZERO_ERROR;
1411
1412 /* Create a formatter for date fields. */
1413 date = DateFormat::createDateInstance(DateFormat::kShort, Locale::getUS());
1414 if (date == nullptr) {
1415 dataerrln("FAIL: createDateInstance failed");
1416 goto FAIL;
1417 }
1418
1419 /* Create a formatter for time fields. */
1420 time = DateFormat::createTimeInstance(DateFormat::kShort, Locale::getUS());
1421 if (time == nullptr) {
1422 errln("FAIL: createTimeInstance failed");
1423 goto FAIL;
1424 }
1425
1426 /* Create a full format for output */
1427 full = DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull,
1428 Locale::getUS());
1429 if (full == nullptr) {
1430 errln("FAIL: createInstance failed");
1431 goto FAIL;
1432 }
1433
1434 /* Create a calendar */
1435 cal = Calendar::createInstance(Locale::getUS(), ec);
1436 if (cal == nullptr || U_FAILURE(ec)) {
1437 errln((UnicodeString)"FAIL: Calendar::createInstance failed with " +
1438 u_errorName(ec));
1439 goto FAIL;
1440 }
1441
1442 /* Parse the date */
1443 cal->clear();
1444 str = UnicodeString("4/5/2001", "");
1445 pos.setIndex(0);
1446 date->parse(str, *cal, pos);
1447 if (pos.getIndex() != str.length()) {
1448 errln((UnicodeString)"FAIL: DateFormat::parse(4/5/2001) failed at " +
1449 pos.getIndex());
1450 goto FAIL;
1451 }
1452
1453 /* Parse the time */
1454 str = UnicodeString("5:45 PM", "");
1455 pos.setIndex(0);
1456 time->parse(str, *cal, pos);
1457 if (pos.getIndex() != str.length()) {
1458 errln((UnicodeString)"FAIL: DateFormat::parse(17:45) failed at " +
1459 pos.getIndex());
1460 goto FAIL;
1461 }
1462
1463 /* Check result */
1464 when = cal->getTime(ec);
1465 if (U_FAILURE(ec)) {
1466 errln((UnicodeString)"FAIL: cal->getTime() failed with " + u_errorName(ec));
1467 goto FAIL;
1468 }
1469 str.truncate(0);
1470 full->format(when, str);
1471 // Thursday, April 5, 2001 5:45:00 PM PDT 986517900000
1472 if (when == 986517900000.0) {
1473 logln("Ok: Parsed result: " + str);
1474 } else {
1475 errln("FAIL: Parsed result: " + str + ", exp 4/5/2001 5:45 PM");
1476 }
1477
1478 FAIL:
1479 delete date;
1480 delete time;
1481 delete full;
1482 delete cal;
1483 }
1484
1485 /**
1486 * Test DateFormat's parsing of space characters. See jitterbug 1916.
1487 */
TestSpaceParsing()1488 void DateFormatTest::TestSpaceParsing() {
1489 const char* DATA[] = {
1490 "yyyy MM dd HH:mm:ss",
1491
1492 // pattern, input, expected parse or nullptr if expect parse failure
1493 "MMMM d yy", " 04 05 06", "2006 04 05 00:00:00",
1494 nullptr, "04 05 06", "2006 04 05 00:00:00",
1495
1496 "MM d yy", " 04 05 06", "2006 04 05 00:00:00",
1497 nullptr, "04 05 06", "2006 04 05 00:00:00",
1498 nullptr, "04/05/06", "2006 04 05 00:00:00",
1499 nullptr, "04-05-06", "2006 04 05 00:00:00",
1500 nullptr, "04.05.06", "2006 04 05 00:00:00",
1501 nullptr, "04 / 05 / 06", "2006 04 05 00:00:00",
1502 nullptr, "Apr / 05/ 06", "2006 04 05 00:00:00",
1503 nullptr, "Apr-05-06", "2006 04 05 00:00:00",
1504 nullptr, "Apr 05, 2006", "2006 04 05 00:00:00",
1505
1506 "MMMM d yy", " Apr 05 06", "2006 04 05 00:00:00",
1507 nullptr, "Apr 05 06", "2006 04 05 00:00:00",
1508 nullptr, "Apr05 06", "2006 04 05 00:00:00",
1509
1510 "hh:mm:ss a", "12:34:56 PM", "1970 01 01 12:34:56",
1511 nullptr, "12:34:56PM", "1970 01 01 12:34:56",
1512 nullptr, "12.34.56PM", "1970 01 01 12:34:56",
1513 nullptr, "12 : 34 : 56 PM", "1970 01 01 12:34:56",
1514
1515 "MM d yy 'at' hh:mm:ss a", "04/05/06 12:34:56 PM", "2006 04 05 12:34:56",
1516
1517 "MMMM dd yyyy hh:mm a", "September 27, 1964 21:56 PM", "1964 09 28 09:56:00",
1518 nullptr, "November 4, 2008 0:13 AM", "2008 11 04 00:13:00",
1519
1520 "HH'h'mm'min'ss's'", "12h34min56s", "1970 01 01 12:34:56",
1521 nullptr, "12h34mi56s", "1970 01 01 12:34:56",
1522 nullptr, "12h34m56s", "1970 01 01 12:34:56",
1523 nullptr, "12:34:56", "1970 01 01 12:34:56"
1524 };
1525 const int32_t DATA_len = UPRV_LENGTHOF(DATA);
1526
1527 expectParse(DATA, DATA_len, Locale("en"));
1528 }
1529
1530 /**
1531 * Test handling of "HHmmss" pattern.
1532 */
TestExactCountFormat()1533 void DateFormatTest::TestExactCountFormat() {
1534 const char* DATA[] = {
1535 "yyyy MM dd HH:mm:ss",
1536
1537 // pattern, input, expected parse or nullptr if expect parse failure
1538 "HHmmss", "123456", "1970 01 01 12:34:56",
1539 nullptr, "12345", "1970 01 01 01:23:45",
1540 nullptr, "1234", nullptr,
1541 nullptr, "00-05", nullptr,
1542 nullptr, "12-34", nullptr,
1543 nullptr, "00+05", nullptr,
1544 "ahhmm", "PM730", "1970 01 01 19:30:00",
1545 };
1546 const int32_t DATA_len = UPRV_LENGTHOF(DATA);
1547
1548 expectParse(DATA, DATA_len, Locale("en"));
1549 }
1550
1551 /**
1552 * Test handling of white space.
1553 */
TestWhiteSpaceParsing()1554 void DateFormatTest::TestWhiteSpaceParsing() {
1555 const char* DATA[] = {
1556 "yyyy MM dd",
1557
1558 // pattern, input, expected parse or null if expect parse failure
1559
1560 // Pattern space run should parse input text space run
1561 "MM d yy", " 04 01 03", "2003 04 01",
1562 nullptr, " 04 01 03 ", "2003 04 01",
1563 };
1564 const int32_t DATA_len = UPRV_LENGTHOF(DATA);
1565
1566 expectParse(DATA, DATA_len, Locale("en"));
1567 }
1568
1569
TestInvalidPattern()1570 void DateFormatTest::TestInvalidPattern() {
1571 UErrorCode ec = U_ZERO_ERROR;
1572 SimpleDateFormat f(UnicodeString("Yesterday"), ec);
1573 if (U_FAILURE(ec)) {
1574 dataerrln("Fail construct SimpleDateFormat: %s", u_errorName(ec));
1575 return;
1576 }
1577 UnicodeString out;
1578 FieldPosition pos;
1579 f.format((UDate)0, out, pos);
1580 logln(out);
1581 // The bug is that the call to format() will crash. By not
1582 // crashing, the test passes.
1583 }
1584
TestGreekMay()1585 void DateFormatTest::TestGreekMay() {
1586 UErrorCode ec = U_ZERO_ERROR;
1587 UDate date = -9896080848000.0;
1588 SimpleDateFormat fmt("EEEE, dd MMMM yyyy h:mm:ss a", Locale("el", "", ""), ec);
1589 if (U_FAILURE(ec)) {
1590 dataerrln("Fail construct SimpleDateFormat: %s", u_errorName(ec));
1591 return;
1592 }
1593 UnicodeString str;
1594 fmt.format(date, str);
1595 ParsePosition pos(0);
1596 UDate d2 = fmt.parse(str, pos);
1597 if (date != d2) {
1598 errln("FAIL: unable to parse strings where case-folding changes length");
1599 }
1600 }
1601
TestStandAloneMonths()1602 void DateFormatTest::TestStandAloneMonths()
1603 {
1604 const char *EN_DATA[] = {
1605 "yyyy MM dd HH:mm:ss",
1606
1607 "yyyy LLLL dd H:mm:ss", "fp", "2004 03 10 16:36:31", "2004 March 10 16:36:31", "2004 03 10 16:36:31",
1608 "yyyy LLL dd H:mm:ss", "fp", "2004 03 10 16:36:31", "2004 Mar 10 16:36:31", "2004 03 10 16:36:31",
1609 "yyyy LLLL dd H:mm:ss", "F", "2004 03 10 16:36:31", "2004 March 10 16:36:31",
1610 "yyyy LLL dd H:mm:ss", "pf", "2004 Mar 10 16:36:31", "2004 03 10 16:36:31", "2004 Mar 10 16:36:31",
1611
1612 "LLLL", "fp", "1970 01 01 0:00:00", "January", "1970 01 01 0:00:00",
1613 "LLLL", "fp", "1970 02 01 0:00:00", "February", "1970 02 01 0:00:00",
1614 "LLLL", "fp", "1970 03 01 0:00:00", "March", "1970 03 01 0:00:00",
1615 "LLLL", "fp", "1970 04 01 0:00:00", "April", "1970 04 01 0:00:00",
1616 "LLLL", "fp", "1970 05 01 0:00:00", "May", "1970 05 01 0:00:00",
1617 "LLLL", "fp", "1970 06 01 0:00:00", "June", "1970 06 01 0:00:00",
1618 "LLLL", "fp", "1970 07 01 0:00:00", "July", "1970 07 01 0:00:00",
1619 "LLLL", "fp", "1970 08 01 0:00:00", "August", "1970 08 01 0:00:00",
1620 "LLLL", "fp", "1970 09 01 0:00:00", "September", "1970 09 01 0:00:00",
1621 "LLLL", "fp", "1970 10 01 0:00:00", "October", "1970 10 01 0:00:00",
1622 "LLLL", "fp", "1970 11 01 0:00:00", "November", "1970 11 01 0:00:00",
1623 "LLLL", "fp", "1970 12 01 0:00:00", "December", "1970 12 01 0:00:00",
1624
1625 "LLL", "fp", "1970 01 01 0:00:00", "Jan", "1970 01 01 0:00:00",
1626 "LLL", "fp", "1970 02 01 0:00:00", "Feb", "1970 02 01 0:00:00",
1627 "LLL", "fp", "1970 03 01 0:00:00", "Mar", "1970 03 01 0:00:00",
1628 "LLL", "fp", "1970 04 01 0:00:00", "Apr", "1970 04 01 0:00:00",
1629 "LLL", "fp", "1970 05 01 0:00:00", "May", "1970 05 01 0:00:00",
1630 "LLL", "fp", "1970 06 01 0:00:00", "Jun", "1970 06 01 0:00:00",
1631 "LLL", "fp", "1970 07 01 0:00:00", "Jul", "1970 07 01 0:00:00",
1632 "LLL", "fp", "1970 08 01 0:00:00", "Aug", "1970 08 01 0:00:00",
1633 "LLL", "fp", "1970 09 01 0:00:00", "Sep", "1970 09 01 0:00:00",
1634 "LLL", "fp", "1970 10 01 0:00:00", "Oct", "1970 10 01 0:00:00",
1635 "LLL", "fp", "1970 11 01 0:00:00", "Nov", "1970 11 01 0:00:00",
1636 "LLL", "fp", "1970 12 01 0:00:00", "Dec", "1970 12 01 0:00:00",
1637 };
1638
1639 const char *CS_DATA[] = {
1640 "yyyy MM dd HH:mm:ss",
1641
1642 "yyyy LLLL dd H:mm:ss", "fp", "2004 04 10 16:36:31", "2004 duben 10 16:36:31", "2004 04 10 16:36:31",
1643 "yyyy MMMM dd H:mm:ss", "fp", "2004 04 10 16:36:31", "2004 dubna 10 16:36:31", "2004 04 10 16:36:31",
1644 "yyyy LLL dd H:mm:ss", "fp", "2004 04 10 16:36:31", "2004 dub 10 16:36:31", "2004 04 10 16:36:31",
1645 "yyyy LLLL dd H:mm:ss", "F", "2004 04 10 16:36:31", "2004 duben 10 16:36:31",
1646 "yyyy MMMM dd H:mm:ss", "F", "2004 04 10 16:36:31", "2004 dubna 10 16:36:31",
1647 "yyyy LLLL dd H:mm:ss", "pf", "2004 duben 10 16:36:31", "2004 04 10 16:36:31", "2004 duben 10 16:36:31",
1648 "yyyy MMMM dd H:mm:ss", "pf", "2004 dubna 10 16:36:31", "2004 04 10 16:36:31", "2004 dubna 10 16:36:31",
1649
1650 "LLLL", "fp", "1970 01 01 0:00:00", "leden", "1970 01 01 0:00:00",
1651 "LLLL", "fp", "1970 02 01 0:00:00", "\\u00FAnor", "1970 02 01 0:00:00",
1652 "LLLL", "fp", "1970 03 01 0:00:00", "b\\u0159ezen", "1970 03 01 0:00:00",
1653 "LLLL", "fp", "1970 04 01 0:00:00", "duben", "1970 04 01 0:00:00",
1654 "LLLL", "fp", "1970 05 01 0:00:00", "kv\\u011Bten", "1970 05 01 0:00:00",
1655 "LLLL", "fp", "1970 06 01 0:00:00", "\\u010Derven", "1970 06 01 0:00:00",
1656 "LLLL", "fp", "1970 07 01 0:00:00", "\\u010Dervenec", "1970 07 01 0:00:00",
1657 "LLLL", "fp", "1970 08 01 0:00:00", "srpen", "1970 08 01 0:00:00",
1658 "LLLL", "fp", "1970 09 01 0:00:00", "z\\u00E1\\u0159\\u00ED", "1970 09 01 0:00:00",
1659 "LLLL", "fp", "1970 10 01 0:00:00", "\\u0159\\u00EDjen", "1970 10 01 0:00:00",
1660 "LLLL", "fp", "1970 11 01 0:00:00", "listopad", "1970 11 01 0:00:00",
1661 "LLLL", "fp", "1970 12 01 0:00:00", "prosinec", "1970 12 01 0:00:00",
1662
1663 "LLL", "fp", "1970 01 01 0:00:00", "led", "1970 01 01 0:00:00",
1664 "LLL", "fp", "1970 02 01 0:00:00", "\\u00FAno", "1970 02 01 0:00:00",
1665 "LLL", "fp", "1970 03 01 0:00:00", "b\\u0159e", "1970 03 01 0:00:00",
1666 "LLL", "fp", "1970 04 01 0:00:00", "dub", "1970 04 01 0:00:00",
1667 "LLL", "fp", "1970 05 01 0:00:00", "kv\\u011B", "1970 05 01 0:00:00",
1668 "LLL", "fp", "1970 06 01 0:00:00", "\\u010Dvn", "1970 06 01 0:00:00",
1669 "LLL", "fp", "1970 07 01 0:00:00", "\\u010Dvc", "1970 07 01 0:00:00",
1670 "LLL", "fp", "1970 08 01 0:00:00", "srp", "1970 08 01 0:00:00",
1671 "LLL", "fp", "1970 09 01 0:00:00", "z\\u00E1\\u0159", "1970 09 01 0:00:00",
1672 "LLL", "fp", "1970 10 01 0:00:00", "\\u0159\\u00EDj", "1970 10 01 0:00:00",
1673 "LLL", "fp", "1970 11 01 0:00:00", "lis", "1970 11 01 0:00:00",
1674 "LLL", "fp", "1970 12 01 0:00:00", "pro", "1970 12 01 0:00:00",
1675 };
1676
1677 expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
1678 expect(CS_DATA, UPRV_LENGTHOF(CS_DATA), Locale("cs", "", ""));
1679 }
1680
TestStandAloneDays()1681 void DateFormatTest::TestStandAloneDays()
1682 {
1683 const char *EN_DATA[] = {
1684 "yyyy MM dd HH:mm:ss",
1685
1686 "cccc", "fp", "1970 01 04 0:00:00", "Sunday", "1970 01 04 0:00:00",
1687 "cccc", "fp", "1970 01 05 0:00:00", "Monday", "1970 01 05 0:00:00",
1688 "cccc", "fp", "1970 01 06 0:00:00", "Tuesday", "1970 01 06 0:00:00",
1689 "cccc", "fp", "1970 01 07 0:00:00", "Wednesday", "1970 01 07 0:00:00",
1690 "cccc", "fp", "1970 01 01 0:00:00", "Thursday", "1970 01 01 0:00:00",
1691 "cccc", "fp", "1970 01 02 0:00:00", "Friday", "1970 01 02 0:00:00",
1692 "cccc", "fp", "1970 01 03 0:00:00", "Saturday", "1970 01 03 0:00:00",
1693
1694 "ccc", "fp", "1970 01 04 0:00:00", "Sun", "1970 01 04 0:00:00",
1695 "ccc", "fp", "1970 01 05 0:00:00", "Mon", "1970 01 05 0:00:00",
1696 "ccc", "fp", "1970 01 06 0:00:00", "Tue", "1970 01 06 0:00:00",
1697 "ccc", "fp", "1970 01 07 0:00:00", "Wed", "1970 01 07 0:00:00",
1698 "ccc", "fp", "1970 01 01 0:00:00", "Thu", "1970 01 01 0:00:00",
1699 "ccc", "fp", "1970 01 02 0:00:00", "Fri", "1970 01 02 0:00:00",
1700 "ccc", "fp", "1970 01 03 0:00:00", "Sat", "1970 01 03 0:00:00",
1701 };
1702
1703 const char *CS_DATA[] = {
1704 "yyyy MM dd HH:mm:ss",
1705
1706 "cccc", "fp", "1970 01 04 0:00:00", "ned\\u011Ble", "1970 01 04 0:00:00",
1707 "cccc", "fp", "1970 01 05 0:00:00", "pond\\u011Bl\\u00ED", "1970 01 05 0:00:00",
1708 "cccc", "fp", "1970 01 06 0:00:00", "\\u00FAter\\u00FD", "1970 01 06 0:00:00",
1709 "cccc", "fp", "1970 01 07 0:00:00", "st\\u0159eda", "1970 01 07 0:00:00",
1710 "cccc", "fp", "1970 01 01 0:00:00", "\\u010Dtvrtek", "1970 01 01 0:00:00",
1711 "cccc", "fp", "1970 01 02 0:00:00", "p\\u00E1tek", "1970 01 02 0:00:00",
1712 "cccc", "fp", "1970 01 03 0:00:00", "sobota", "1970 01 03 0:00:00",
1713
1714 "ccc", "fp", "1970 01 04 0:00:00", "ne", "1970 01 04 0:00:00",
1715 "ccc", "fp", "1970 01 05 0:00:00", "po", "1970 01 05 0:00:00",
1716 "ccc", "fp", "1970 01 06 0:00:00", "\\u00FAt", "1970 01 06 0:00:00",
1717 "ccc", "fp", "1970 01 07 0:00:00", "st", "1970 01 07 0:00:00",
1718 "ccc", "fp", "1970 01 01 0:00:00", "\\u010Dt", "1970 01 01 0:00:00",
1719 "ccc", "fp", "1970 01 02 0:00:00", "p\\u00E1", "1970 01 02 0:00:00",
1720 "ccc", "fp", "1970 01 03 0:00:00", "so", "1970 01 03 0:00:00",
1721 };
1722
1723 expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
1724 expect(CS_DATA, UPRV_LENGTHOF(CS_DATA), Locale("cs", "", ""));
1725 }
1726
TestShortDays()1727 void DateFormatTest::TestShortDays()
1728 {
1729 const char *EN_DATA[] = {
1730 "yyyy MM dd HH:mm:ss",
1731
1732 "EEEEEE, MMM d y", "fp", "2013 01 13 0:00:00", "Su, Jan 13 2013", "2013 01 13 0:00:00",
1733 "EEEEEE, MMM d y", "fp", "2013 01 16 0:00:00", "We, Jan 16 2013", "2013 01 16 0:00:00",
1734 "EEEEEE d", "fp", "1970 01 17 0:00:00", "Sa 17", "1970 01 17 0:00:00",
1735 "cccccc d", "fp", "1970 01 17 0:00:00", "Sa 17", "1970 01 17 0:00:00",
1736 "cccccc", "fp", "1970 01 03 0:00:00", "Sa", "1970 01 03 0:00:00",
1737 };
1738 const char *SV_DATA[] = {
1739 "yyyy MM dd HH:mm:ss",
1740
1741 "EEEEEE d MMM y", "fp", "2013 01 13 0:00:00", "s\\u00F6 13 jan. 2013", "2013 01 13 0:00:00",
1742 "EEEEEE d MMM y", "fp", "2013 01 16 0:00:00", "on 16 jan. 2013", "2013 01 16 0:00:00",
1743 "EEEEEE d", "fp", "1970 01 17 0:00:00", "l\\u00F6 17", "1970 01 17 0:00:00",
1744 "cccccc d", "fp", "1970 01 17 0:00:00", "l\\u00F6 17", "1970 01 17 0:00:00",
1745 "cccccc", "fp", "1970 01 03 0:00:00", "l\\u00F6", "1970 01 03 0:00:00",
1746 };
1747 expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
1748 expect(SV_DATA, UPRV_LENGTHOF(SV_DATA), Locale("sv", "", ""));
1749 }
1750
TestNarrowNames()1751 void DateFormatTest::TestNarrowNames()
1752 {
1753 const char *EN_DATA[] = {
1754 "yyyy MM dd HH:mm:ss",
1755
1756 "yyyy MMMMM dd H:mm:ss", "2004 03 10 16:36:31", "2004 M 10 16:36:31",
1757 "yyyy LLLLL dd H:mm:ss", "2004 03 10 16:36:31", "2004 M 10 16:36:31",
1758
1759 "MMMMM", "1970 01 01 0:00:00", "J",
1760 "MMMMM", "1970 02 01 0:00:00", "F",
1761 "MMMMM", "1970 03 01 0:00:00", "M",
1762 "MMMMM", "1970 04 01 0:00:00", "A",
1763 "MMMMM", "1970 05 01 0:00:00", "M",
1764 "MMMMM", "1970 06 01 0:00:00", "J",
1765 "MMMMM", "1970 07 01 0:00:00", "J",
1766 "MMMMM", "1970 08 01 0:00:00", "A",
1767 "MMMMM", "1970 09 01 0:00:00", "S",
1768 "MMMMM", "1970 10 01 0:00:00", "O",
1769 "MMMMM", "1970 11 01 0:00:00", "N",
1770 "MMMMM", "1970 12 01 0:00:00", "D",
1771
1772 "LLLLL", "1970 01 01 0:00:00", "J",
1773 "LLLLL", "1970 02 01 0:00:00", "F",
1774 "LLLLL", "1970 03 01 0:00:00", "M",
1775 "LLLLL", "1970 04 01 0:00:00", "A",
1776 "LLLLL", "1970 05 01 0:00:00", "M",
1777 "LLLLL", "1970 06 01 0:00:00", "J",
1778 "LLLLL", "1970 07 01 0:00:00", "J",
1779 "LLLLL", "1970 08 01 0:00:00", "A",
1780 "LLLLL", "1970 09 01 0:00:00", "S",
1781 "LLLLL", "1970 10 01 0:00:00", "O",
1782 "LLLLL", "1970 11 01 0:00:00", "N",
1783 "LLLLL", "1970 12 01 0:00:00", "D",
1784
1785 "EEEEE", "1970 01 04 0:00:00", "S",
1786 "EEEEE", "1970 01 05 0:00:00", "M",
1787 "EEEEE", "1970 01 06 0:00:00", "T",
1788 "EEEEE", "1970 01 07 0:00:00", "W",
1789 "EEEEE", "1970 01 01 0:00:00", "T",
1790 "EEEEE", "1970 01 02 0:00:00", "F",
1791 "EEEEE", "1970 01 03 0:00:00", "S",
1792
1793 "ccccc", "1970 01 04 0:00:00", "S",
1794 "ccccc", "1970 01 05 0:00:00", "M",
1795 "ccccc", "1970 01 06 0:00:00", "T",
1796 "ccccc", "1970 01 07 0:00:00", "W",
1797 "ccccc", "1970 01 01 0:00:00", "T",
1798 "ccccc", "1970 01 02 0:00:00", "F",
1799 "ccccc", "1970 01 03 0:00:00", "S",
1800
1801 "h:mm a", "2015 01 01 10:00:00", "10:00 AM",
1802 "h:mm a", "2015 01 01 22:00:00", "10:00 PM",
1803 "h:mm aaaaa", "2015 01 01 10:00:00", "10:00 a",
1804 "h:mm aaaaa", "2015 01 01 22:00:00", "10:00 p",
1805 };
1806
1807 const char *CS_DATA[] = {
1808 "yyyy MM dd HH:mm:ss",
1809
1810 "yyyy LLLLL dd H:mm:ss", "2004 04 10 16:36:31", "2004 4 10 16:36:31",
1811 "yyyy MMMMM dd H:mm:ss", "2004 04 10 16:36:31", "2004 4 10 16:36:31",
1812
1813 "MMMMM", "1970 01 01 0:00:00", "1",
1814 "MMMMM", "1970 02 01 0:00:00", "2",
1815 "MMMMM", "1970 03 01 0:00:00", "3",
1816 "MMMMM", "1970 04 01 0:00:00", "4",
1817 "MMMMM", "1970 05 01 0:00:00", "5",
1818 "MMMMM", "1970 06 01 0:00:00", "6",
1819 "MMMMM", "1970 07 01 0:00:00", "7",
1820 "MMMMM", "1970 08 01 0:00:00", "8",
1821 "MMMMM", "1970 09 01 0:00:00", "9",
1822 "MMMMM", "1970 10 01 0:00:00", "10",
1823 "MMMMM", "1970 11 01 0:00:00", "11",
1824 "MMMMM", "1970 12 01 0:00:00", "12",
1825
1826 "LLLLL", "1970 01 01 0:00:00", "1",
1827 "LLLLL", "1970 02 01 0:00:00", "2",
1828 "LLLLL", "1970 03 01 0:00:00", "3",
1829 "LLLLL", "1970 04 01 0:00:00", "4",
1830 "LLLLL", "1970 05 01 0:00:00", "5",
1831 "LLLLL", "1970 06 01 0:00:00", "6",
1832 "LLLLL", "1970 07 01 0:00:00", "7",
1833 "LLLLL", "1970 08 01 0:00:00", "8",
1834 "LLLLL", "1970 09 01 0:00:00", "9",
1835 "LLLLL", "1970 10 01 0:00:00", "10",
1836 "LLLLL", "1970 11 01 0:00:00", "11",
1837 "LLLLL", "1970 12 01 0:00:00", "12",
1838
1839 "EEEEE", "1970 01 04 0:00:00", "N",
1840 "EEEEE", "1970 01 05 0:00:00", "P",
1841 "EEEEE", "1970 01 06 0:00:00", "\\u00DA",
1842 "EEEEE", "1970 01 07 0:00:00", "S",
1843 "EEEEE", "1970 01 01 0:00:00", "\\u010C",
1844 "EEEEE", "1970 01 02 0:00:00", "P",
1845 "EEEEE", "1970 01 03 0:00:00", "S",
1846
1847 "ccccc", "1970 01 04 0:00:00", "N",
1848 "ccccc", "1970 01 05 0:00:00", "P",
1849 "ccccc", "1970 01 06 0:00:00", "\\u00DA",
1850 "ccccc", "1970 01 07 0:00:00", "S",
1851 "ccccc", "1970 01 01 0:00:00", "\\u010C",
1852 "ccccc", "1970 01 02 0:00:00", "P",
1853 "ccccc", "1970 01 03 0:00:00", "S",
1854
1855 "h:mm a", "2015 01 01 10:00:00", "10:00 dop.",
1856 "h:mm a", "2015 01 01 22:00:00", "10:00 odp.",
1857 "h:mm aaaaa", "2015 01 01 10:00:00", "10:00 dop.",
1858 "h:mm aaaaa", "2015 01 01 22:00:00", "10:00 odp.",
1859 };
1860
1861 const char *CA_DATA[] = {
1862 "yyyy MM dd HH:mm:ss",
1863
1864 "h:mm a", "2015 01 01 10:00:00", "10:00 a.\\u00A0m.",
1865 "h:mm a", "2015 01 01 22:00:00", "10:00 p.\\u00A0m.",
1866 "h:mm aaaaa", "2015 01 01 10:00:00", "10:00 a.\\u202Fm.",
1867 "h:mm aaaaa", "2015 01 01 22:00:00", "10:00 p.\\u202Fm.",
1868 };
1869
1870 expectFormat(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
1871 expectFormat(CS_DATA, UPRV_LENGTHOF(CS_DATA), Locale("cs", "", ""));
1872 expectFormat(CA_DATA, UPRV_LENGTHOF(CA_DATA), Locale("ca", "", ""));
1873 }
1874
TestEras()1875 void DateFormatTest::TestEras()
1876 {
1877 const char *EN_DATA[] = {
1878 "yyyy MM dd",
1879
1880 "MMMM dd yyyy G", "fp", "1951 07 17", "July 17 1951 AD", "1951 07 17",
1881 "MMMM dd yyyy GG", "fp", "1951 07 17", "July 17 1951 AD", "1951 07 17",
1882 "MMMM dd yyyy GGG", "fp", "1951 07 17", "July 17 1951 AD", "1951 07 17",
1883 "MMMM dd yyyy GGGG", "fp", "1951 07 17", "July 17 1951 Anno Domini", "1951 07 17",
1884
1885 "MMMM dd yyyy G", "fp", "-438 07 17", "July 17 0439 BC", "-438 07 17",
1886 "MMMM dd yyyy GG", "fp", "-438 07 17", "July 17 0439 BC", "-438 07 17",
1887 "MMMM dd yyyy GGG", "fp", "-438 07 17", "July 17 0439 BC", "-438 07 17",
1888 "MMMM dd yyyy GGGG", "fp", "-438 07 17", "July 17 0439 Before Christ", "-438 07 17",
1889 };
1890
1891 expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
1892 }
1893
TestQuarters()1894 void DateFormatTest::TestQuarters()
1895 {
1896 const char *EN_DATA[] = {
1897 "yyyy MM dd",
1898
1899 "Q", "fp", "1970 01 01", "1", "1970 01 01",
1900 "QQ", "fp", "1970 04 01", "02", "1970 04 01",
1901 "QQQ", "fp", "1970 07 01", "Q3", "1970 07 01",
1902 "QQQQ", "fp", "1970 10 01", "4th quarter", "1970 10 01",
1903 "QQQQQ", "fp", "1970 10 01", "4", "1970 10 01",
1904
1905 "q", "fp", "1970 01 01", "1", "1970 01 01",
1906 "qq", "fp", "1970 04 01", "02", "1970 04 01",
1907 "qqq", "fp", "1970 07 01", "Q3", "1970 07 01",
1908 "qqqq", "fp", "1970 10 01", "4th quarter", "1970 10 01",
1909 "qqqqq", "fp", "1970 10 01", "4", "1970 10 01",
1910
1911 "Qyy", "fp", "2015 04 01", "215", "2015 04 01",
1912 "QQyy", "fp", "2015 07 01", "0315", "2015 07 01",
1913 };
1914 const char *ES_MX_DATA[] = {
1915 "yyyy MM dd",
1916
1917 "QQQQ y", "fp", "1970 01 01", "1.er trimestre 1970", "1970 01 01",
1918 "QQQ y", "fp", "1970 01 01", "T1 1970", "1970 01 01",
1919 "QQQQQ y", "fp", "1970 01 01", "1 1970", "1970 01 01",
1920 "qqqq", "fp", "1970 01 01", "1.er trimestre", "1970 01 01",
1921 "qqq", "fp", "1970 01 01", "T1", "1970 01 01",
1922 "qqqqq", "fp", "1970 01 01", "1T", "1970 01 01",
1923 };
1924
1925 expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
1926 expect(ES_MX_DATA, UPRV_LENGTHOF(ES_MX_DATA), Locale("es", "MX", ""));
1927 }
1928
1929 /**
1930 * Test parsing. Input is an array that starts with the following
1931 * header:
1932 *
1933 * [0] = pattern string to parse [i+2] with
1934 *
1935 * followed by test cases, each of which is 3 array elements:
1936 *
1937 * [i] = pattern, or nullptr to reuse prior pattern
1938 * [i+1] = input string
1939 * [i+2] = expected parse result (parsed with pattern [0])
1940 *
1941 * If expect parse failure, then [i+2] should be nullptr.
1942 */
expectParse(const char ** data,int32_t data_length,const Locale & loc)1943 void DateFormatTest::expectParse(const char** data, int32_t data_length,
1944 const Locale& loc) {
1945 const UDate FAIL = (UDate) -1;
1946 const UnicodeString FAIL_STR("parse failure");
1947 int32_t i = 0;
1948
1949 UErrorCode ec = U_ZERO_ERROR;
1950 SimpleDateFormat fmt("", loc, ec);
1951 SimpleDateFormat ref(data[i++], loc, ec);
1952 SimpleDateFormat gotfmt("G yyyy MM dd HH:mm:ss z", loc, ec);
1953 if (U_FAILURE(ec)) {
1954 dataerrln("FAIL: SimpleDateFormat constructor - %s", u_errorName(ec));
1955 return;
1956 }
1957
1958 const char* currentPat = nullptr;
1959 while (i<data_length) {
1960 const char* pattern = data[i++];
1961 const char* input = data[i++];
1962 const char* expected = data[i++];
1963
1964 ec = U_ZERO_ERROR;
1965 if (pattern != nullptr) {
1966 fmt.applyPattern(pattern);
1967 currentPat = pattern;
1968 }
1969 UDate got = fmt.parse(input, ec);
1970 UnicodeString gotstr(FAIL_STR);
1971 if (U_FAILURE(ec)) {
1972 got = FAIL;
1973 } else {
1974 gotstr.remove();
1975 gotfmt.format(got, gotstr);
1976 }
1977
1978 UErrorCode ec2 = U_ZERO_ERROR;
1979 UDate exp = FAIL;
1980 UnicodeString expstr(FAIL_STR);
1981 if (expected != nullptr) {
1982 expstr = expected;
1983 exp = ref.parse(expstr, ec2);
1984 if (U_FAILURE(ec2)) {
1985 // This only happens if expected is in wrong format --
1986 // should never happen once test is debugged.
1987 errln("FAIL: Internal test error");
1988 return;
1989 }
1990 }
1991
1992 if (got == exp) {
1993 logln((UnicodeString)"Ok: " + input + " x " +
1994 currentPat + " => " + gotstr);
1995 } else {
1996 errln((UnicodeString)"FAIL: " + input + " x " +
1997 currentPat + " => " + gotstr + ", expected " +
1998 expstr);
1999 }
2000 }
2001 }
2002
2003 /**
2004 * Test formatting and parsing. Input is an array that starts
2005 * with the following header:
2006 *
2007 * [0] = pattern string to parse [i+2] with
2008 *
2009 * followed by test cases, each of which is 3 array elements:
2010 *
2011 * [i] = pattern, or null to reuse prior pattern
2012 * [i+1] = control string, either "fp", "pf", or "F".
2013 * [i+2..] = data strings
2014 *
2015 * The number of data strings depends on the control string.
2016 * Examples:
2017 * 1. "y/M/d H:mm:ss.SS", "fp", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.56", "2004 03 10 16:36:31.560",
2018 * 'f': Format date [i+2] (as parsed using pattern [0]) and expect string [i+3].
2019 * 'p': Parse string [i+3] and expect date [i+4].
2020 *
2021 * 2. "y/M/d H:mm:ss.SSS", "F", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.567"
2022 * 'F': Format date [i+2] and expect string [i+3],
2023 * then parse string [i+3] and expect date [i+2].
2024 *
2025 * 3. "y/M/d H:mm:ss.SSSS", "pf", "2004/3/10 16:36:31.5679", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.5670",
2026 * 'p': Parse string [i+2] and expect date [i+3].
2027 * 'f': Format date [i+3] and expect string [i+4].
2028 */
expect(const char ** data,int32_t data_length,const Locale & loc)2029 void DateFormatTest::expect(const char** data, int32_t data_length,
2030 const Locale& loc) {
2031 int32_t i = 0;
2032 UErrorCode ec = U_ZERO_ERROR;
2033 UnicodeString str, str2;
2034 SimpleDateFormat fmt("", loc, ec);
2035 SimpleDateFormat ref(data[i++], loc, ec);
2036 SimpleDateFormat univ("EE G yyyy MM dd HH:mm:ss.SSS z", loc, ec);
2037 if (U_FAILURE(ec)) {
2038 dataerrln("Fail construct SimpleDateFormat: %s", u_errorName(ec));
2039 return;
2040 }
2041
2042 UnicodeString currentPat;
2043 while (i<data_length) {
2044 const char* pattern = data[i++];
2045 if (pattern != nullptr) {
2046 fmt.applyPattern(pattern);
2047 currentPat = pattern;
2048 }
2049
2050 const char* control = data[i++];
2051
2052 if (uprv_strcmp(control, "fp") == 0) {
2053 // 'f'
2054 const char* datestr = data[i++];
2055 const char* string = data[i++];
2056 UDate date = ref.parse(ctou(datestr), ec);
2057 if (!assertSuccess("parse", ec)) return;
2058 assertEquals((UnicodeString)"loc " + ctou(loc.getName()) + " \"" + currentPat + "\".format(" + datestr + ")",
2059 ctou(string),
2060 fmt.format(date, str.remove()));
2061 // 'p'
2062 datestr = data[i++];
2063 date = ref.parse(ctou(datestr), ec);
2064 if (!assertSuccess("parse", ec)) return;
2065 UDate parsedate = fmt.parse(ctou(string), ec);
2066 if (assertSuccess((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")", ec)) {
2067 assertEquals((UnicodeString)"loc " + ctou(loc.getName()) + " \"" + currentPat + "\".parse(" + string + ")",
2068 univ.format(date, str.remove()),
2069 univ.format(parsedate, str2.remove()));
2070 }
2071 }
2072
2073 else if (uprv_strcmp(control, "pf") == 0) {
2074 // 'p'
2075 const char* string = data[i++];
2076 const char* datestr = data[i++];
2077 UDate date = ref.parse(ctou(datestr), ec);
2078 if (!assertSuccess("parse", ec)) return;
2079 UDate parsedate = fmt.parse(ctou(string), ec);
2080 if (assertSuccess((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")", ec)) {
2081 assertEquals((UnicodeString)"loc " + ctou(loc.getName()) + " \"" + currentPat + "\".parse(" + string + ")",
2082 univ.format(date, str.remove()),
2083 univ.format(parsedate, str2.remove()));
2084 }
2085 // 'f'
2086 string = data[i++];
2087 assertEquals((UnicodeString)"loc " + ctou(loc.getName()) + " \"" + currentPat + "\".format(" + datestr + ")",
2088 ctou(string),
2089 fmt.format(date, str.remove()));
2090 }
2091
2092 else if (uprv_strcmp(control, "F") == 0) {
2093 const char* datestr = data[i++];
2094 const char* string = data[i++];
2095 UDate date = ref.parse(ctou(datestr), ec);
2096 if (!assertSuccess("parse", ec)) return;
2097 assertEquals((UnicodeString)"loc " + ctou(loc.getName()) + " \"" + currentPat + "\".format(" + datestr + ")",
2098 ctou(string),
2099 fmt.format(date, str.remove()));
2100
2101 UDate parsedate = fmt.parse(string, ec);
2102 if (assertSuccess((UnicodeString)"\"" + currentPat + "\".parse(" + string + ")", ec)) {
2103 assertEquals((UnicodeString)"loc " + ctou(loc.getName()) + " \"" + currentPat + "\".parse(" + string + ")",
2104 univ.format(date, str.remove()),
2105 univ.format(parsedate, str2.remove()));
2106 }
2107 }
2108
2109 else {
2110 errln((UnicodeString)"FAIL: Invalid control string " + control);
2111 return;
2112 }
2113 }
2114 }
2115
2116 /**
2117 * Test formatting. Input is an array that starts
2118 * with the following header:
2119 *
2120 * [0] = pattern string to parse [i+2] with
2121 *
2122 * followed by test cases, each of which is 3 array elements:
2123 *
2124 * [i] = pattern, or null to reuse prior pattern
2125 * [i+1] = data string a
2126 * [i+2] = data string b
2127 *
2128 * Examples:
2129 * Format date [i+1] and expect string [i+2].
2130 *
2131 * "y/M/d H:mm:ss.SSSS", "2004/3/10 16:36:31.5679", "2004 03 10 16:36:31.567"
2132 */
expectFormat(const char ** data,int32_t data_length,const Locale & loc)2133 void DateFormatTest::expectFormat(const char** data, int32_t data_length,
2134 const Locale& loc) {
2135 int32_t i = 0;
2136 UErrorCode ec = U_ZERO_ERROR;
2137 UnicodeString str, str2;
2138 SimpleDateFormat fmt("", loc, ec);
2139 SimpleDateFormat ref(data[i++], loc, ec);
2140 SimpleDateFormat univ("EE G yyyy MM dd HH:mm:ss.SSS z", loc, ec);
2141 if (U_FAILURE(ec)) {
2142 dataerrln("Fail construct SimpleDateFormat: %s", u_errorName(ec));
2143 return;
2144 }
2145
2146 UnicodeString currentPat;
2147
2148 while (i<data_length) {
2149 const char* pattern = data[i++];
2150 if (pattern != nullptr) {
2151 fmt.applyPattern(pattern);
2152 currentPat = pattern;
2153 }
2154
2155 const char* datestr = data[i++];
2156 const char* string = data[i++];
2157 UDate date = ref.parse(ctou(datestr), ec);
2158 if (!assertSuccess("parse", ec)) return;
2159 assertEquals((UnicodeString)"loc " + ctou(loc.getName()) + " \"" + currentPat + "\".format(" + datestr + ")",
2160 ctou(string),
2161 fmt.format(date, str.remove()));
2162 }
2163 }
2164
TestGenericTime()2165 void DateFormatTest::TestGenericTime() {
2166 const Locale en("en");
2167 // Note: We no longer parse strings in different styles.
2168 /*
2169 const char* ZDATA[] = {
2170 "yyyy MM dd HH:mm zzz",
2171 // round trip
2172 "y/M/d H:mm zzzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Standard Time",
2173 "y/M/d H:mm zzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
2174 "y/M/d H:mm vvvv", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
2175 "y/M/d H:mm v", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PT",
2176 // non-generic timezone string influences dst offset even if wrong for date/time
2177 "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PDT", "2004 01 01 01:00 PDT", "2004/1/1 0:00 PST",
2178 "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 PDT", "2004 01 01 01:00 PDT", "2004/1/1 0:00 Pacific Time",
2179 "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PST", "2004 07 01 02:00 PDT", "2004/7/1 2:00 PDT",
2180 "y/M/d H:mm vvvv", "pf", "2004/7/1 1:00 PST", "2004 07 01 02:00 PDT", "2004/7/1 2:00 Pacific Time",
2181 // generic timezone generates dst offset appropriate for local time
2182 "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
2183 "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
2184 "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PDT",
2185 "y/M/d H:mm vvvv", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 Pacific Time",
2186 // daylight savings time transition edge cases.
2187 // time to parse does not really exist, PT interpreted as earlier time
2188 "y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PT", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PDT",
2189 "y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PST", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PDT",
2190 "y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PDT", "2005 04 03 01:30 PST", "2005/4/3 1:30 PST",
2191 "y/M/d H:mm v", "pf", "2005/4/3 2:30 PT", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PT",
2192 "y/M/d H:mm v", "pf", "2005/4/3 2:30 PST", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PT",
2193 "y/M/d H:mm v", "pf", "2005/4/3 2:30 PDT", "2005 04 03 01:30 PST", "2005/4/3 1:30 PT",
2194 "y/M/d H:mm", "pf", "2005/4/3 2:30", "2005 04 03 03:30 PDT", "2005/4/3 3:30",
2195 // time to parse is ambiguous, PT interpreted as later time
2196 "y/M/d H:mm zzz", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30 PST",
2197 "y/M/d H:mm v", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30 PT",
2198 "y/M/d H:mm", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30",
2199
2200 "y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PT", "2004 10 31 01:30 PST", "2004/10/31 1:30 PST",
2201 "y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PST", "2004 10 31 01:30 PST", "2004/10/31 1:30 PST",
2202 "y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PDT", "2004 10 31 01:30 PDT", "2004/10/31 1:30 PDT",
2203 "y/M/d H:mm v", "pf", "2004/10/31 1:30 PT", "2004 10 31 01:30 PST", "2004/10/31 1:30 PT",
2204 "y/M/d H:mm v", "pf", "2004/10/31 1:30 PST", "2004 10 31 01:30 PST", "2004/10/31 1:30 PT",
2205 "y/M/d H:mm v", "pf", "2004/10/31 1:30 PDT", "2004 10 31 01:30 PDT", "2004/10/31 1:30 PT",
2206 "y/M/d H:mm", "pf", "2004/10/31 1:30", "2004 10 31 01:30 PST", "2004/10/31 1:30",
2207 };
2208 */
2209 const char* ZDATA[] = {
2210 "yyyy MM dd HH:mm zzz",
2211 // round trip
2212 "y/M/d H:mm zzzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Standard Time",
2213 "y/M/d H:mm zzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
2214 "y/M/d H:mm vvvv", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
2215 "y/M/d H:mm v", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PT",
2216 // non-generic timezone string influences dst offset even if wrong for date/time
2217 "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PDT", "2004 01 01 01:00 PDT", "2004/1/1 0:00 PST",
2218 "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PST", "2004 07 01 02:00 PDT", "2004/7/1 2:00 PDT",
2219 // generic timezone generates dst offset appropriate for local time
2220 "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PST", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
2221 "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 Pacific Time", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
2222 "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PDT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PDT",
2223 "y/M/d H:mm vvvv", "pf", "2004/7/1 1:00 Pacific Time", "2004 07 01 01:00 PDT", "2004/7/1 1:00 Pacific Time",
2224 // daylight savings time transition edge cases.
2225 // time to parse does not really exist, PT interpreted as earlier time
2226 "y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PST", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PDT",
2227 "y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PDT", "2005 04 03 01:30 PST", "2005/4/3 1:30 PST",
2228 "y/M/d H:mm v", "pf", "2005/4/3 2:30 PT", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PT",
2229 "y/M/d H:mm", "pf", "2005/4/3 2:30", "2005 04 03 03:30 PDT", "2005/4/3 3:30",
2230 // time to parse is ambiguous, PT interpreted as later time
2231 "y/M/d H:mm v", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30 PT",
2232 "y/M/d H:mm", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30",
2233
2234 "y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PST", "2004 10 31 01:30 PST", "2004/10/31 1:30 PST",
2235 "y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PDT", "2004 10 31 01:30 PDT", "2004/10/31 1:30 PDT",
2236 "y/M/d H:mm v", "pf", "2004/10/31 1:30 PT", "2004 10 31 01:30 PST", "2004/10/31 1:30 PT",
2237 "y/M/d H:mm", "pf", "2004/10/31 1:30", "2004 10 31 01:30 PST", "2004/10/31 1:30",
2238 };
2239
2240 const int32_t ZDATA_length = UPRV_LENGTHOF(ZDATA);
2241 expect(ZDATA, ZDATA_length, en);
2242
2243 UErrorCode status = U_ZERO_ERROR;
2244
2245 logln("cross format/parse tests"); // Note: We no longer support cross format/parse
2246 UnicodeString basepat("yy/MM/dd H:mm ");
2247 SimpleDateFormat formats[] = {
2248 SimpleDateFormat(basepat + "vvv", en, status),
2249 SimpleDateFormat(basepat + "vvvv", en, status),
2250 SimpleDateFormat(basepat + "zzz", en, status),
2251 SimpleDateFormat(basepat + "zzzz", en, status)
2252 };
2253 if (U_FAILURE(status)) {
2254 dataerrln("Fail construct SimpleDateFormat: %s", u_errorName(status));
2255 return;
2256 }
2257 const int32_t formats_length = UPRV_LENGTHOF(formats);
2258
2259 UnicodeString test;
2260 SimpleDateFormat univ("yyyy MM dd HH:mm zzz", en, status);
2261 ASSERT_OK(status);
2262 const UnicodeString times[] = {
2263 "2004 01 02 03:04 PST",
2264 "2004 07 08 09:10 PDT"
2265 };
2266 int32_t times_length = UPRV_LENGTHOF(times);
2267 for (int i = 0; i < times_length; ++i) {
2268 UDate d = univ.parse(times[i], status);
2269 logln(UnicodeString("\ntime: ") + d);
2270 for (int j = 0; j < formats_length; ++j) {
2271 test.remove();
2272 formats[j].format(d, test);
2273 logln("\ntest: '" + test + "'");
2274 for (int k = 0; k < formats_length; ++k) {
2275 UDate t = formats[k].parse(test, status);
2276 if (U_SUCCESS(status)) {
2277 if (d != t) {
2278 errln((UnicodeString)"FAIL: format " + k +
2279 " incorrectly parsed output of format " + j +
2280 " (" + test + "), returned " +
2281 dateToString(t) + " instead of " + dateToString(d));
2282 } else {
2283 logln((UnicodeString)"OK: format " + k + " parsed ok");
2284 }
2285 } else if (status == U_PARSE_ERROR) {
2286 errln((UnicodeString)"FAIL: format " + k +
2287 " could not parse output of format " + j +
2288 " (" + test + ")");
2289 }
2290 }
2291 }
2292 }
2293 }
2294
TestGenericTimeZoneOrder()2295 void DateFormatTest::TestGenericTimeZoneOrder() {
2296 // generic times should parse the same no matter what the placement of the time zone string
2297
2298 // Note: We no longer support cross style format/parse
2299
2300 //const char* XDATA[] = {
2301 // "yyyy MM dd HH:mm zzz",
2302 // // standard time, explicit daylight/standard
2303 // "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
2304 // "y/M/d zzz H:mm", "pf", "2004/1/1 PT 1:00", "2004 01 01 01:00 PST", "2004/1/1 PST 1:00",
2305 // "zzz y/M/d H:mm", "pf", "PT 2004/1/1 1:00", "2004 01 01 01:00 PST", "PST 2004/1/1 1:00",
2306
2307 // // standard time, generic
2308 // "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 PT", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
2309 // "y/M/d vvvv H:mm", "pf", "2004/1/1 PT 1:00", "2004 01 01 01:00 PST", "2004/1/1 Pacific Time 1:00",
2310 // "vvvv y/M/d H:mm", "pf", "PT 2004/1/1 1:00", "2004 01 01 01:00 PST", "Pacific Time 2004/1/1 1:00",
2311
2312 // // dahylight time, explicit daylight/standard
2313 // "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PDT",
2314 // "y/M/d zzz H:mm", "pf", "2004/7/1 PT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 PDT 1:00",
2315 // "zzz y/M/d H:mm", "pf", "PT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "PDT 2004/7/1 1:00",
2316
2317 // // daylight time, generic
2318 // "y/M/d H:mm vvvv", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 Pacific Time",
2319 // "y/M/d vvvv H:mm", "pf", "2004/7/1 PT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 Pacific Time 1:00",
2320 // "vvvv y/M/d H:mm", "pf", "PT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "Pacific Time 2004/7/1 1:00",
2321 //};
2322 const char* XDATA[] = {
2323 "yyyy MM dd HH:mm zzz",
2324 // standard time, explicit daylight/standard
2325 "y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PST", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
2326 "y/M/d zzz H:mm", "pf", "2004/1/1 PST 1:00", "2004 01 01 01:00 PST", "2004/1/1 PST 1:00",
2327 "zzz y/M/d H:mm", "pf", "PST 2004/1/1 1:00", "2004 01 01 01:00 PST", "PST 2004/1/1 1:00",
2328
2329 // standard time, generic
2330 "y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 Pacific Time", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
2331 "y/M/d vvvv H:mm", "pf", "2004/1/1 Pacific Time 1:00", "2004 01 01 01:00 PST", "2004/1/1 Pacific Time 1:00",
2332 "vvvv y/M/d H:mm", "pf", "Pacific Time 2004/1/1 1:00", "2004 01 01 01:00 PST", "Pacific Time 2004/1/1 1:00",
2333
2334 // dahylight time, explicit daylight/standard
2335 "y/M/d H:mm zzz", "pf", "2004/7/1 1:00 PDT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PDT",
2336 "y/M/d zzz H:mm", "pf", "2004/7/1 PDT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 PDT 1:00",
2337 "zzz y/M/d H:mm", "pf", "PDT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "PDT 2004/7/1 1:00",
2338
2339 // daylight time, generic
2340 "y/M/d H:mm v", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 PT",
2341 "y/M/d v H:mm", "pf", "2004/7/1 PT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 PT 1:00",
2342 "v y/M/d H:mm", "pf", "PT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "PT 2004/7/1 1:00",
2343 };
2344 const int32_t XDATA_length = UPRV_LENGTHOF(XDATA);
2345 Locale en("en");
2346 expect(XDATA, XDATA_length, en);
2347 }
2348
TestZTimeZoneParsing()2349 void DateFormatTest::TestZTimeZoneParsing() {
2350 UErrorCode status = U_ZERO_ERROR;
2351 const Locale en("en");
2352 UnicodeString test;
2353 //SimpleDateFormat univ("yyyy-MM-dd'T'HH:mm Z", en, status);
2354 SimpleDateFormat univ("HH:mm Z", en, status);
2355 if (failure(status, "construct SimpleDateFormat", true)) return;
2356 const TimeZone *t = TimeZone::getGMT();
2357 univ.setTimeZone(*t);
2358
2359 univ.setLenient(false);
2360 ParsePosition pp(0);
2361 struct {
2362 UnicodeString input;
2363 UnicodeString expected_result;
2364 } tests[] = {
2365 { "11:00 -0200", "13:00 +0000" },
2366 { "11:00 +0200", "09:00 +0000" },
2367 { "11:00 +0400", "07:00 +0000" },
2368 { "11:00 +0530", "05:30 +0000" }
2369 };
2370
2371 UnicodeString result;
2372 int32_t tests_length = UPRV_LENGTHOF(tests);
2373 for (int i = 0; i < tests_length; ++i) {
2374 pp.setIndex(0);
2375 UDate d = univ.parse(tests[i].input, pp);
2376 if(pp.getIndex() != tests[i].input.length()){
2377 errln("Test %i: setZoneString() did not succeed. Consumed: %i instead of %i",
2378 i, pp.getIndex(), tests[i].input.length());
2379 return;
2380 }
2381 result.remove();
2382 univ.format(d, result);
2383 if(result != tests[i].expected_result) {
2384 errln("Expected " + tests[i].expected_result
2385 + " got " + result);
2386 return;
2387 }
2388 logln("SUCCESS: Parsed " + tests[i].input
2389 + " got " + result
2390 + " expected " + tests[i].expected_result);
2391 }
2392 }
2393
TestHost()2394 void DateFormatTest::TestHost()
2395 {
2396 #if U_PLATFORM_USES_ONLY_WIN32_API
2397 Win32DateTimeTest::testLocales(this);
2398 #endif
2399 }
2400
2401 // Relative Date Tests
2402
TestRelative(int daysdelta,const Locale & loc,const char * expectChars)2403 void DateFormatTest::TestRelative(int daysdelta,
2404 const Locale& loc,
2405 const char *expectChars) {
2406 char banner[25];
2407 snprintf(banner, sizeof(banner), "%d", daysdelta);
2408 UnicodeString bannerStr(banner, "");
2409
2410 UErrorCode status = U_ZERO_ERROR;
2411
2412 FieldPosition pos(FieldPosition::DONT_CARE);
2413 UnicodeString test;
2414 Locale en("en");
2415 DateFormat *fullrelative = DateFormat::createDateInstance(DateFormat::kFullRelative, loc);
2416
2417 if (fullrelative == nullptr) {
2418 dataerrln("DateFormat::createDateInstance(DateFormat::kFullRelative, %s) returned nullptr", loc.getName());
2419 return;
2420 }
2421
2422 DateFormat *full = DateFormat::createDateInstance(DateFormat::kFull , loc);
2423
2424 if (full == nullptr) {
2425 errln("DateFormat::createDateInstance(DateFormat::kFull, %s) returned nullptr", loc.getName());
2426 return;
2427 }
2428
2429 DateFormat *en_full = DateFormat::createDateInstance(DateFormat::kFull, en);
2430
2431 if (en_full == nullptr) {
2432 errln("DateFormat::createDateInstance(DateFormat::kFull, en) returned nullptr");
2433 return;
2434 }
2435
2436 DateFormat *en_fulltime = DateFormat::createDateTimeInstance(DateFormat::kFull,DateFormat::kFull,en);
2437
2438 if (en_fulltime == nullptr) {
2439 errln("DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, en) returned nullptr");
2440 return;
2441 }
2442
2443 UnicodeString result;
2444 UnicodeString normalResult;
2445 UnicodeString expect;
2446 UnicodeString parseResult;
2447
2448 Calendar *c = Calendar::createInstance(status);
2449
2450 // Today = Today
2451 c->setTime(Calendar::getNow(), status);
2452 if(daysdelta != 0) {
2453 c->add(Calendar::DATE,daysdelta,status);
2454 }
2455 ASSERT_OK(status);
2456
2457 // calculate the expected string
2458 if(expectChars != nullptr) {
2459 expect = expectChars;
2460 } else {
2461 full->format(*c, expect, pos); // expected = normal full
2462 }
2463
2464 fullrelative ->format(*c, result, pos);
2465 en_full ->format(*c, normalResult, pos);
2466
2467 if(result != expect) {
2468 errln("FAIL: Relative Format ["+bannerStr+"] of "+normalResult+" failed, expected "+expect+" but got " + result);
2469 } else {
2470 logln("PASS: Relative Format ["+bannerStr+"] of "+normalResult+" got " + result);
2471 }
2472
2473
2474 //verify
2475 UDate d = fullrelative->parse(result, status);
2476 ASSERT_OK(status);
2477
2478 UnicodeString parseFormat; // parse rel->format full
2479 en_full->format(d, parseFormat, status);
2480
2481 UnicodeString origFormat;
2482 en_full->format(*c, origFormat, pos);
2483
2484 if(parseFormat!=origFormat) {
2485 errln("FAIL: Relative Parse ["+bannerStr+"] of "+result+" failed, expected "+parseFormat+" but got "+origFormat);
2486 } else {
2487 logln("PASS: Relative Parse ["+bannerStr+"] of "+result+" passed, got "+parseFormat);
2488 }
2489
2490 delete full;
2491 delete fullrelative;
2492 delete en_fulltime;
2493 delete en_full;
2494 delete c;
2495 }
2496
2497
TestRelative()2498 void DateFormatTest::TestRelative()
2499 {
2500 Locale en("en");
2501 TestRelative( 0, en, "today");
2502 TestRelative(-1, en, "yesterday");
2503 TestRelative( 1, en, "tomorrow");
2504 TestRelative( 2, en, nullptr);
2505 TestRelative( -2, en, nullptr);
2506 TestRelative( 3, en, nullptr);
2507 TestRelative( -3, en, nullptr);
2508 TestRelative( 300, en, nullptr);
2509 TestRelative( -300, en, nullptr);
2510 }
2511
TestRelativeClone()2512 void DateFormatTest::TestRelativeClone()
2513 {
2514 /*
2515 Verify that a cloned formatter gives the same results
2516 and is useable after the original has been deleted.
2517 */
2518 UErrorCode status = U_ZERO_ERROR;
2519 Locale loc("en");
2520 UDate now = Calendar::getNow();
2521 DateFormat *full = DateFormat::createDateInstance(DateFormat::kFullRelative, loc);
2522 if (full == nullptr) {
2523 dataerrln("FAIL: Can't create Relative date instance");
2524 return;
2525 }
2526 UnicodeString result1;
2527 full->format(now, result1, status);
2528 Format *fullClone = full->clone();
2529 delete full;
2530 full = nullptr;
2531
2532 UnicodeString result2;
2533 fullClone->format(now, result2, status);
2534 ASSERT_OK(status);
2535 if (result1 != result2) {
2536 errln("FAIL: Clone returned different result from non-clone.");
2537 }
2538 delete fullClone;
2539 }
2540
TestHostClone()2541 void DateFormatTest::TestHostClone()
2542 {
2543 /*
2544 Verify that a cloned formatter gives the same results
2545 and is useable after the original has been deleted.
2546 */
2547 // This is mainly important on Windows.
2548 UErrorCode status = U_ZERO_ERROR;
2549 Locale loc("en_US@compat=host");
2550 UDate now = Calendar::getNow();
2551 DateFormat *full = DateFormat::createDateInstance(DateFormat::kFull, loc);
2552 if (full == nullptr) {
2553 dataerrln("FAIL: Can't create host date instance");
2554 return;
2555 }
2556 UnicodeString result1;
2557 full->format(now, result1, status);
2558 Format *fullClone = full->clone();
2559 delete full;
2560 full = nullptr;
2561
2562 UnicodeString result2;
2563 fullClone->format(now, result2, status);
2564 ASSERT_OK(status);
2565 if (result1 != result2) {
2566 errln("FAIL: Clone returned different result from non-clone.");
2567 }
2568 delete fullClone;
2569 }
2570
TestHebrewClone()2571 void DateFormatTest::TestHebrewClone()
2572 {
2573 /*
2574 Verify that a cloned formatter gives the same results
2575 and is useable after the original has been deleted.
2576 */
2577 UErrorCode status = U_ZERO_ERROR;
2578 Locale loc("he@calendar=hebrew");
2579 UDate now = Calendar::getNow();
2580 LocalPointer<DateFormat> fmt(
2581 DateFormat::createDateInstance(DateFormat::kLong, loc));
2582 if (fmt.isNull()) {
2583 dataerrln("FAIL: Can't create Hebrew date instance");
2584 return;
2585 }
2586 UnicodeString result1;
2587 fmt->format(now, result1, status);
2588 LocalPointer<Format> fmtClone(fmt->clone());
2589
2590 // free fmt to be sure that fmtClone is independent of fmt.
2591 fmt.adoptInstead(nullptr);
2592
2593 UnicodeString result2;
2594 fmtClone->format(now, result2, status);
2595 ASSERT_OK(status);
2596 if (result1 != result2) {
2597 errln("FAIL: Clone returned different result from non-clone.");
2598 }
2599 }
2600
getActualAndValidLocales(const Format & fmt,Locale & valid,Locale & actual)2601 static UBool getActualAndValidLocales(
2602 const Format &fmt, Locale &valid, Locale &actual) {
2603 const SimpleDateFormat* dat = dynamic_cast<const SimpleDateFormat*>(&fmt);
2604 if (dat == nullptr) {
2605 return false;
2606 }
2607 const DateFormatSymbols *sym = dat->getDateFormatSymbols();
2608 if (sym == nullptr) {
2609 return false;
2610 }
2611 UErrorCode status = U_ZERO_ERROR;
2612 valid = sym->getLocale(ULOC_VALID_LOCALE, status);
2613 actual = sym->getLocale(ULOC_ACTUAL_LOCALE, status);
2614 return U_SUCCESS(status);
2615 }
2616
TestDateFormatSymbolsClone()2617 void DateFormatTest::TestDateFormatSymbolsClone()
2618 {
2619 /*
2620 Verify that a cloned formatter gives the same results
2621 and is useable after the original has been deleted.
2622 */
2623 Locale loc("de_CH_LUCERNE");
2624 LocalPointer<DateFormat> fmt(
2625 DateFormat::createDateInstance(DateFormat::kDefault, loc));
2626 if (fmt.isNull()) {
2627 dataerrln("FAIL: DateFormat::createDateInstance failed for %s", loc.getName());
2628 return;
2629 }
2630 Locale valid1;
2631 Locale actual1;
2632 if (!getActualAndValidLocales(*fmt, valid1, actual1)) {
2633 dataerrln("FAIL: Could not fetch valid + actual locales");
2634 return;
2635 }
2636 LocalPointer<Format> fmtClone(fmt->clone());
2637
2638 // Free fmt to be sure that fmtClone is really independent of fmt.
2639 fmt.adoptInstead(nullptr);
2640 Locale valid2;
2641 Locale actual2;
2642 if (!getActualAndValidLocales(*fmtClone, valid2, actual2)) {
2643 errln("FAIL: Could not fetch valid + actual locales");
2644 return;
2645 }
2646 if (valid1 != valid2 || actual1 != actual2) {
2647 errln("Date format symbol locales of clone don't match original");
2648 }
2649 }
2650
TestTimeZoneDisplayName()2651 void DateFormatTest::TestTimeZoneDisplayName()
2652 {
2653 // This test data was ported from ICU4J. Don't know why the 6th column in there because it's not being
2654 // used currently.
2655 const char *fallbackTests[][6] = {
2656 { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
2657 { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
2658 { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZZ", "-08:00", "-8:00" },
2659 { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "PST", "America/Los_Angeles" },
2660 { "en", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "Pacific Standard Time", "America/Los_Angeles" },
2661 { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
2662 { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
2663 { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "PDT", "America/Los_Angeles" },
2664 { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "Pacific Daylight Time", "America/Los_Angeles" },
2665 { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "PT", "America/Los_Angeles" },
2666 { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "Pacific Time", "America/Los_Angeles" },
2667 { "en", "America/Los_Angeles", "2004-07-15T00:00:00Z", "VVVV", "Los Angeles Time", "America/Los_Angeles" },
2668 { "en_GB", "America/Los_Angeles", "2004-01-15T12:00:00Z", "z", "GMT-8", "America/Los_Angeles" },
2669 { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "Z", "-0700", "-7:00" },
2670 { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
2671 { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "z", "MST", "America/Phoenix" },
2672 { "en", "America/Phoenix", "2004-01-15T00:00:00Z", "zzzz", "Mountain Standard Time", "America/Phoenix" },
2673 { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
2674 { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
2675 { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "z", "MST", "America/Phoenix" },
2676 { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "zzzz", "Mountain Standard Time", "America/Phoenix" },
2677 { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "v", "MST", "America/Phoenix" },
2678 { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "vvvv", "Mountain Standard Time", "America/Phoenix" },
2679 { "en", "America/Phoenix", "2004-07-15T00:00:00Z", "VVVV", "Phoenix Time", "America/Phoenix" },
2680
2681 { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2682 { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2683 { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2684 { "en", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
2685 { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2686 { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2687 { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2688 { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
2689 { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires Time", "America/Buenos_Aires" },
2690 { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentina Standard Time", "America/Buenos_Aires" },
2691 { "en", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "VVVV", "Buenos Aires Time", "America/Buenos_Aires" },
2692
2693 { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2694 { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2695 { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2696 { "en", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
2697 { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2698 { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2699 { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2700 { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentina Standard Time", "-3:00" },
2701 { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires Time", "America/Buenos_Aires" },
2702 { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentina Standard Time", "America/Buenos_Aires" },
2703 { "en", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "VVVV", "Buenos Aires Time", "America/Buenos_Aires" },
2704
2705 { "en", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
2706 { "en", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
2707 { "en", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
2708 { "en", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "Cuba Standard Time", "-5:00" },
2709 { "en", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
2710 { "en", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
2711 { "en", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
2712 { "en", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "Cuba Daylight Time", "-4:00" },
2713 { "en", "America/Havana", "2004-07-15T00:00:00Z", "v", "Cuba Time", "America/Havana" },
2714 { "en", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "Cuba Time", "America/Havana" },
2715 { "en", "America/Havana", "2004-07-15T00:00:00Z", "VVVV", "Cuba Time", "America/Havana" },
2716
2717 { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
2718 { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
2719 { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
2720 { "en", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "Australian Eastern Daylight Time", "+11:00" },
2721 { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
2722 { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
2723 { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
2724 { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "Australian Eastern Standard Time", "+10:00" },
2725 { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "Sydney Time", "Australia/Sydney" },
2726 { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "Eastern Australia Time", "Australia/Sydney" },
2727 { "en", "Australia/ACT", "2004-07-15T00:00:00Z", "VVVV", "Sydney Time", "Australia/Sydney" },
2728
2729 { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
2730 { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
2731 { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
2732 { "en", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "Australian Eastern Daylight Time", "+11:00" },
2733 { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
2734 { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
2735 { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
2736 { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "Australian Eastern Standard Time", "+10:00" },
2737 { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "Sydney Time", "Australia/Sydney" },
2738 { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "Eastern Australia Time", "Australia/Sydney" },
2739 { "en", "Australia/Sydney", "2004-07-15T00:00:00Z", "VVVV", "Sydney Time", "Australia/Sydney" },
2740
2741 { "en", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
2742 { "en", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
2743 { "en", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
2744 { "en", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "Greenwich Mean Time", "+0:00" },
2745 { "en", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
2746 { "en", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
2747 { "en", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "Europe/London" },
2748 { "en", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "British Summer Time", "Europe/London" },
2749 // icu en.txt has exemplar city for this time zone
2750 { "en", "Europe/London", "2004-07-15T00:00:00Z", "v", "United Kingdom Time", "Europe/London" },
2751 { "en", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "United Kingdom Time", "Europe/London" },
2752 { "en", "Europe/London", "2004-07-15T00:00:00Z", "VVVV", "United Kingdom Time", "Europe/London" },
2753
2754 { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2755 { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2756 { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2757 { "en", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
2758 { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2759 { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2760 { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2761 { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
2762 { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
2763 { "en", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
2764
2765 // JB#5150
2766 { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
2767 { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
2768 { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
2769 { "en", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "India Standard Time", "+5:30" },
2770 { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
2771 { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
2772 { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
2773 { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "India Standard Time", "+5:30" },
2774 { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "India Time", "Asia/Calcutta" },
2775 { "en", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "India Standard Time", "Asia/Calcutta" },
2776
2777 // Proper CLDR primary zone support #9733
2778 { "en", "America/Santiago", "2013-01-01T00:00:00Z", "VVVV", "Chile Time", "America/Santiago" },
2779 { "en", "Pacific/Easter", "2013-01-01T00:00:00Z", "VVVV", "Easter Time", "Pacific/Easter" },
2780
2781 // ==========
2782
2783 { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
2784 { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
2785 { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "-8:00" },
2786 { "de", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "Nordamerikanische Westk\\u00fcsten-Normalzeit", "-8:00" },
2787 { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
2788 { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
2789 { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "-7:00" },
2790 { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "Nordamerikanische Westk\\u00fcsten-Sommerzeit", "-7:00" },
2791 { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "Los Angeles (Ortszeit)", "America/Los_Angeles" },
2792 { "de", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "Nordamerikanische Westk\\u00fcstenzeit", "America/Los_Angeles" },
2793
2794 { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2795 { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2796 { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2797 { "de", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
2798 { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2799 { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2800 { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2801 { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
2802 { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires (Ortszeit)", "America/Buenos_Aires" },
2803 { "de", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentinische Normalzeit", "America/Buenos_Aires" },
2804
2805 { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2806 { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2807 { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2808 { "de", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
2809 { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2810 { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2811 { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2812 { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "Argentinische Normalzeit", "-3:00" },
2813 { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "Buenos Aires (Ortszeit)", "America/Buenos_Aires" },
2814 { "de", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "Argentinische Normalzeit", "America/Buenos_Aires" },
2815
2816 { "de", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
2817 { "de", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
2818 { "de", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
2819 { "de", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "Kubanische Normalzeit", "-5:00" },
2820 { "de", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
2821 { "de", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
2822 { "de", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
2823 { "de", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "Kubanische Sommerzeit", "-4:00" },
2824 { "de", "America/Havana", "2004-07-15T00:00:00Z", "v", "Kuba (Ortszeit)", "America/Havana" },
2825 { "de", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "Kubanische Zeit", "America/Havana" },
2826 // added to test proper fallback of country name
2827 { "de_CH", "America/Havana", "2004-07-15T00:00:00Z", "v", "Kuba (Ortszeit)", "America/Havana" },
2828 { "de_CH", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "Kubanische Zeit", "America/Havana" },
2829
2830 { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
2831 { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
2832 { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
2833 { "de", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "Ostaustralische Sommerzeit", "+11:00" },
2834 { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
2835 { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
2836 { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
2837 { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "Ostaustralische Normalzeit", "+10:00" },
2838 { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "Sydney (Ortszeit)", "Australia/Sydney" },
2839 { "de", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "Ostaustralische Zeit", "Australia/Sydney" },
2840
2841 { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
2842 { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
2843 { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
2844 { "de", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "Ostaustralische Sommerzeit", "+11:00" },
2845 { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
2846 { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
2847 { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
2848 { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "Ostaustralische Normalzeit", "+10:00" },
2849 { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "Sydney (Ortszeit)", "Australia/Sydney" },
2850 { "de", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "Ostaustralische Zeit", "Australia/Sydney" },
2851
2852 { "de", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
2853 { "de", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
2854 { "de", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
2855 { "de", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "Mittlere Greenwich-Zeit", "+0:00" },
2856 { "de", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
2857 { "de", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
2858 { "de", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
2859 { "de", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "Britische Sommerzeit", "+1:00" },
2860 { "de", "Europe/London", "2004-07-15T00:00:00Z", "v", "Vereinigtes K\\u00f6nigreich (Ortszeit)", "Europe/London" },
2861 { "de", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "Vereinigtes K\\u00f6nigreich (Ortszeit)", "Europe/London" },
2862
2863 { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2864 { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2865 { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2866 { "de", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
2867 { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2868 { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2869 { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2870 { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
2871 { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
2872 { "de", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
2873
2874 // JB#5150
2875 { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
2876 { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
2877 { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
2878 { "de", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "Indische Normalzeit", "+5:30" },
2879 { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
2880 { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
2881 { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
2882 { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "Indische Normalzeit", "+5:30" },
2883 { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "Indien (Ortszeit)", "Asia/Calcutta" },
2884 { "de", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "Indische Normalzeit", "Asia/Calcutta" },
2885
2886 // ==========
2887
2888 { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
2889 { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
2890 { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "America/Los_Angeles" },
2891 { "zh", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\\u5317\\u7f8e\\u592a\\u5e73\\u6d0b\\u6807\\u51c6\\u65f6\\u95f4", "America/Los_Angeles" },
2892 { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
2893 { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
2894 { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "America/Los_Angeles" },
2895 { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\\u5317\\u7f8e\\u592a\\u5e73\\u6d0b\\u590f\\u4ee4\\u65f6\\u95f4", "America/Los_Angeles" },
2896 // icu zh.txt has exemplar city for this time zone
2897 { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u6D1B\\u6749\\u77F6\\u65F6\\u95F4", "America/Los_Angeles" },
2898 { "zh", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\\u5317\\u7f8e\\u592a\\u5e73\\u6d0b\\u65f6\\u95f4", "America/Los_Angeles" },
2899
2900 { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2901 { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2902 { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2903 { "zh", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "-3:00" },
2904 { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2905 { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2906 { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2907 { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "-3:00" },
2908 { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u5E03\\u5B9C\\u8BFA\\u65AF\\u827E\\u5229\\u65AF\\u65F6\\u95F4", "America/Buenos_Aires" },
2909 { "zh", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "America/Buenos_Aires" },
2910
2911 { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2912 { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2913 { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2914 { "zh", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "-3:00" },
2915 { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2916 { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2917 { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2918 { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "-3:00" },
2919 { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u5E03\\u5B9C\\u8BFA\\u65AF\\u827E\\u5229\\u65AF\\u65F6\\u95F4", "America/Buenos_Aires" },
2920 { "zh", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u963f\\u6839\\u5ef7\\u6807\\u51c6\\u65f6\\u95f4", "America/Buenos_Aires" },
2921
2922 { "zh", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
2923 { "zh", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
2924 { "zh", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
2925 { "zh", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\\u53e4\\u5df4\\u6807\\u51c6\\u65f6\\u95f4", "-5:00" },
2926 { "zh", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
2927 { "zh", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
2928 { "zh", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
2929 { "zh", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "\\u53e4\\u5df4\\u590f\\u4ee4\\u65f6\\u95f4", "-4:00" },
2930 { "zh", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u53e4\\u5df4\\u65f6\\u95f4", "America/Havana" },
2931 { "zh", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u53e4\\u5df4\\u65f6\\u95f4", "America/Havana" },
2932
2933 { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
2934 { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
2935 { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
2936 { "zh", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u590f\\u4ee4\\u65f6\\u95f4", "+11:00" },
2937 { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
2938 { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
2939 { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
2940 { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u6807\\u51c6\\u65f6\\u95f4", "+10:00" },
2941 // icu zh.txt does not have info for this time zone
2942 { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u6089\\u5C3C\\u65F6\\u95F4", "Australia/Sydney" },
2943 { "zh", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u65f6\\u95f4", "Australia/Sydney" },
2944
2945 { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
2946 { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
2947 { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
2948 { "zh", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u590f\\u4ee4\\u65f6\\u95f4", "+11:00" },
2949 { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
2950 { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
2951 { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
2952 { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u6807\\u51c6\\u65f6\\u95f4", "+10:00" },
2953 { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u6089\\u5C3C\\u65F6\\u95F4", "Australia/Sydney" },
2954 { "zh", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u6fb3\\u5927\\u5229\\u4e9a\\u4e1c\\u90e8\\u65f6\\u95f4", "Australia/Sydney" },
2955
2956 { "zh", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
2957 { "zh", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
2958 { "zh", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
2959 { "zh", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
2960 { "zh", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
2961 { "zh", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u683C\\u6797\\u5C3C\\u6CBB\\u6807\\u51C6\\u65F6\\u95F4", "+0:00" },
2962 { "zh", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
2963 { "zh", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
2964 { "zh", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
2965 { "zh", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\\u82f1\\u56fd\\u590f\\u4ee4\\u65f6\\u95f4", "+1:00" },
2966 { "zh", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u82f1\\u56fd\\u65f6\\u95f4", "Europe/London" },
2967 { "zh", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u82f1\\u56fd\\u65f6\\u95f4", "Europe/London" },
2968 { "zh", "Europe/London", "2004-07-15T00:00:00Z", "VVVV", "\\u82f1\\u56fd\\u65f6\\u95f4", "Europe/London" },
2969
2970 { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
2971 { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2972 { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2973 { "zh", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
2974 { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
2975 { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
2976 { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
2977 { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
2978 { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
2979 { "zh", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
2980
2981 // JB#5150
2982 { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
2983 { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
2984 { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
2985 { "zh", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\\u5370\\u5ea6\\u65f6\\u95f4", "+5:30" },
2986 { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
2987 { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
2988 { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
2989 { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\\u5370\\u5ea6\\u65f6\\u95f4", "+5:30" },
2990 { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u5370\\u5ea6\\u65f6\\u95f4", "Asia/Calcutta" },
2991 { "zh", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u5370\\u5ea6\\u65f6\\u95f4", "Asia/Calcutta" },
2992
2993 // ==========
2994
2995 { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
2996 { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
2997 { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "-8:00" },
2998 { "hi", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\\u0909\\u0924\\u094d\\u0924\\u0930\\u0940 \\u0905\\u092e\\u0947\\u0930\\u093f\\u0915\\u0940 \\u092a\\u094d\\u0930\\u0936\\u093e\\u0902\\u0924 \\u092e\\u093e\\u0928\\u0915 \\u0938\\u092e\\u092f", "-8:00" },
2999 { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
3000 { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
3001 { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "-7:00" },
3002 { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\\u0909\\u0924\\u094d\\u0924\\u0930\\u0940 \\u0905\\u092e\\u0947\\u0930\\u093f\\u0915\\u0940 \\u092a\\u094d\\u0930\\u0936\\u093e\\u0902\\u0924 \\u0921\\u0947\\u0932\\u093e\\u0907\\u091f \\u0938\\u092e\\u092f", "-7:00" },
3003 { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u0932\\u0949\\u0938 \\u090f\\u0902\\u091c\\u093f\\u0932\\u094d\\u0938 \\u0938\\u092e\\u092f", "America/Los_Angeles" },
3004 { "hi", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\\u0909\\u0924\\u094d\\u0924\\u0930\\u0940 \\u0905\\u092e\\u0947\\u0930\\u093f\\u0915\\u0940 \\u092a\\u094d\\u0930\\u0936\\u093e\\u0902\\u0924 \\u0938\\u092e\\u092f", "America/Los_Angeles" },
3005
3006 { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3007 { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3008 { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3009 { "hi", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u0905\\u0930\\u094D\\u091C\\u0947\\u0902\\u091F\\u0940\\u0928\\u093E \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "-3:00" },
3010 { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3011 { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3012 { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3013 { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u0905\\u0930\\u094D\\u091C\\u0947\\u0902\\u091F\\u0940\\u0928\\u093E \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "-3:00" },
3014 { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u092C\\u094D\\u092F\\u0942\\u0928\\u0938 \\u0906\\u092F\\u0930\\u0938 \\u0938\\u092E\\u092F", "America/Buenos_Aires" },
3015 { "hi", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u0905\\u0930\\u094D\\u091C\\u0947\\u0902\\u091F\\u0940\\u0928\\u093E \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "America/Buenos_Aires" },
3016
3017 { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3018 { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3019 { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3020 { "hi", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u0905\\u0930\\u094D\\u091C\\u0947\\u0902\\u091F\\u0940\\u0928\\u093E \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "-3:00" },
3021 { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3022 { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3023 { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3024 { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u0905\\u0930\\u094D\\u091C\\u0947\\u0902\\u091F\\u0940\\u0928\\u093E \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "-3:00" },
3025 { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u092C\\u094D\\u092F\\u0942\\u0928\\u0938 \\u0906\\u092F\\u0930\\u0938 \\u0938\\u092E\\u092F", "America/Buenos_Aires" },
3026 { "hi", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u0905\\u0930\\u094D\\u091C\\u0947\\u0902\\u091F\\u0940\\u0928\\u093E \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "America/Buenos_Aires" },
3027
3028 { "hi", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
3029 { "hi", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
3030 { "hi", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
3031 { "hi", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\\u0915\\u094d\\u092f\\u0942\\u092c\\u093e \\u092e\\u093e\\u0928\\u0915 \\u0938\\u092e\\u092f", "-5:00" },
3032 { "hi", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
3033 { "hi", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
3034 { "hi", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
3035 { "hi", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "\\u0915\\u094d\\u092f\\u0942\\u092c\\u093e \\u0921\\u0947\\u0932\\u093e\\u0907\\u091f \\u0938\\u092e\\u092f", "-4:00" },
3036 { "hi", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u0915\\u094d\\u092f\\u0942\\u092c\\u093e \\u0938\\u092E\\u092F", "America/Havana" },
3037 { "hi", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u0915\\u094d\\u092f\\u0942\\u092c\\u093e \\u0938\\u092e\\u092f", "America/Havana" },
3038
3039 { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3040 { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
3041 { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
3042 { "hi", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\\u0911\\u0938\\u094d\\u200d\\u091f\\u094d\\u0930\\u0947\\u0932\\u093f\\u092f\\u093e\\u0908 \\u092a\\u0942\\u0930\\u094d\\u0935\\u0940 \\u0921\\u0947\\u0932\\u093e\\u0907\\u091f \\u0938\\u092e\\u092f", "+11:00" },
3043 { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3044 { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
3045 { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
3046 { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "\\u0911\\u0938\\u094d\\u200d\\u091f\\u094d\\u0930\\u0947\\u0932\\u093f\\u092f\\u093e\\u0908 \\u092a\\u0942\\u0930\\u094d\\u0935\\u0940 \\u092e\\u093e\\u0928\\u0915 \\u0938\\u092e\\u092f", "+10:00" },
3047 { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u0938\\u093F\\u0921\\u0928\\u0940 \\u0938\\u092E\\u092F", "Australia/Sydney" },
3048 { "hi", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\\u092a\\u0942\\u0930\\u094d\\u0935\\u0940 \\u0911\\u0938\\u094d\\u091f\\u094d\\u0930\\u0947\\u0932\\u093f\\u092f\\u093e \\u0938\\u092e\\u092f", "Australia/Sydney" },
3049
3050 { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3051 { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
3052 { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
3053 { "hi", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\\u0911\\u0938\\u094d\\u200d\\u091f\\u094d\\u0930\\u0947\\u0932\\u093f\\u092f\\u093e\\u0908 \\u092a\\u0942\\u0930\\u094d\\u0935\\u0940 \\u0921\\u0947\\u0932\\u093e\\u0907\\u091f \\u0938\\u092e\\u092f", "+11:00" },
3054 { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3055 { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
3056 { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
3057 { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "\\u0911\\u0938\\u094d\\u200d\\u091f\\u094d\\u0930\\u0947\\u0932\\u093f\\u092f\\u093e\\u0908 \\u092a\\u0942\\u0930\\u094d\\u0935\\u0940 \\u092e\\u093e\\u0928\\u0915 \\u0938\\u092e\\u092f", "+10:00" },
3058 { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u0938\\u093F\\u0921\\u0928\\u0940 \\u0938\\u092E\\u092F", "Australia/Sydney" },
3059 { "hi", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u092a\\u0942\\u0930\\u094d\\u0935\\u0940 \\u0911\\u0938\\u094d\\u091f\\u094d\\u0930\\u0947\\u0932\\u093f\\u092f\\u093e \\u0938\\u092e\\u092f", "Australia/Sydney" },
3060
3061 { "hi", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
3062 { "hi", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
3063 { "hi", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
3064 { "hi", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u0917\\u094d\\u0930\\u0940\\u0928\\u0935\\u093f\\u091a \\u092e\\u0940\\u0928 \\u091f\\u093e\\u0907\\u092e", "+0:00" },
3065 { "hi", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
3066 { "hi", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
3067 { "hi", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
3068 { "hi", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\\u092c\\u094d\\u0930\\u093f\\u091f\\u093f\\u0936 \\u0917\\u094d\\u0930\\u0940\\u0937\\u094d\\u092e\\u0915\\u093e\\u0932\\u0940\\u0928 \\u0938\\u092e\\u092f", "+1:00" },
3069 { "hi", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u092f\\u0942\\u0928\\u093e\\u0907\\u091f\\u0947\\u0921 \\u0915\\u093f\\u0902\\u0917\\u0921\\u092e \\u0938\\u092e\\u092f", "Europe/London" },
3070 { "hi", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u092f\\u0942\\u0928\\u093e\\u0907\\u091f\\u0947\\u0921 \\u0915\\u093f\\u0902\\u0917\\u0921\\u092e \\u0938\\u092e\\u092f", "Europe/London" },
3071
3072 { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3073 { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3074 { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3075 { "hi", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3076 { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3077 { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3078 { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3079 { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3080 { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
3081 { "hi", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
3082
3083 { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
3084 { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
3085 { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "IST", "+5:30" },
3086 { "hi", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\\u092D\\u093E\\u0930\\u0924\\u0940\\u092F \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "+5:30" },
3087 { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
3088 { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
3089 { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "IST", "+05:30" },
3090 { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\\u092D\\u093E\\u0930\\u0924\\u0940\\u092F \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "+5:30" },
3091 { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "IST", "Asia/Calcutta" },
3092 { "hi", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u092D\\u093E\\u0930\\u0924\\u0940\\u092F \\u092E\\u093E\\u0928\\u0915 \\u0938\\u092E\\u092F", "Asia/Calcutta" },
3093
3094 // ==========
3095
3096 { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
3097 { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-08:00", "-8:00" },
3098 { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-8", "America/Los_Angeles" },
3099 { "bg", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\\u0421\\u0435\\u0432\\u0435\\u0440\\u043d\\u043e\\u0430\\u043c\\u0435\\u0440\\u0438\\u043a\\u0430\\u043d\\u0441\\u043a\\u043e \\u0442\\u0438\\u0445\\u043e\\u043e\\u043a\\u0435\\u0430\\u043d\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "America/Los_Angeles" },
3100 { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
3101 { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-07:00", "-7:00" },
3102 { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-7", "America/Los_Angeles" },
3103 { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\\u0421\\u0435\\u0432\\u0435\\u0440\\u043d\\u043e\\u0430\\u043c\\u0435\\u0440\\u0438\\u043a\\u0430\\u043d\\u0441\\u043a\\u043e \\u0442\\u0438\\u0445\\u043e\\u043e\\u043a\\u0435\\u0430\\u043d\\u0441\\u043a\\u043e \\u043b\\u044f\\u0442\\u043d\\u043e \\u0447\\u0430\\u0441\\u043e\\u0432\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "America/Los_Angeles" },
3104 // icu bg.txt has exemplar city for this time zone
3105 { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u041B\\u043E\\u0441 \\u0410\\u043D\\u0434\\u0436\\u0435\\u043B\\u0438\\u0441", "America/Los_Angeles" },
3106 { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\\u0421\\u0435\\u0432\\u0435\\u0440\\u043d\\u043e\\u0430\\u043c\\u0435\\u0440\\u0438\\u043a\\u0430\\u043d\\u0441\\u043a\\u043e \\u0442\\u0438\\u0445\\u043e\\u043e\\u043a\\u0435\\u0430\\u043d\\u0441\\u043a\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "America/Los_Angeles" },
3107 { "bg", "America/Los_Angeles", "2004-07-15T00:00:00Z", "VVVV", "\\u041B\\u043E\\u0441 \\u0410\\u043D\\u0434\\u0436\\u0435\\u043B\\u0438\\u0441", "America/Los_Angeles" },
3108
3109 { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3110 { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3111 { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3112 { "bg", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u0410\\u0440\\u0436\\u0435\\u043D\\u0442\\u0438\\u043D\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "-3:00" },
3113 { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3114 { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3115 { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3116 { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u0410\\u0440\\u0436\\u0435\\u043D\\u0442\\u0438\\u043D\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "-3:00" },
3117 { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u0411\\u0443\\u0435\\u043D\\u043E\\u0441 \\u0410\\u0439\\u0440\\u0435\\u0441", "America/Buenos_Aires" },
3118 { "bg", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u0410\\u0440\\u0436\\u0435\\u043D\\u0442\\u0438\\u043D\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "America/Buenos_Aires" },
3119
3120 { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3121 { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3122 { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3123 { "bg", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u0410\\u0440\\u0436\\u0435\\u043D\\u0442\\u0438\\u043D\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "-3:00" },
3124 { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3125 { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3126 { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3127 { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u0410\\u0440\\u0436\\u0435\\u043D\\u0442\\u0438\\u043D\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "-3:00" },
3128 // icu bg.txt does not have info for this time zone
3129 { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u0411\\u0443\\u0435\\u043D\\u043E\\u0441 \\u0410\\u0439\\u0440\\u0435\\u0441", "America/Buenos_Aires" },
3130 { "bg", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u0410\\u0440\\u0436\\u0435\\u043D\\u0442\\u0438\\u043D\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "America/Buenos_Aires" },
3131
3132 { "bg", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
3133 { "bg", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-05:00", "-5:00" },
3134 { "bg", "America/Havana", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-5", "-5:00" },
3135 { "bg", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\\u041a\\u0443\\u0431\\u0438\\u043d\\u0441\\u043a\\u043e \\u0441\\u0442\\u0430\\u043d\\u0434\\u0430\\u0440\\u0442\\u043d\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "-5:00" },
3136 { "bg", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
3137 { "bg", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-04:00", "-4:00" },
3138 { "bg", "America/Havana", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-4", "-4:00" },
3139 { "bg", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "\\u041a\\u0443\\u0431\\u0438\\u043d\\u0441\\u043a\\u043e \\u043b\\u044f\\u0442\\u043d\\u043e \\u0447\\u0430\\u0441\\u043e\\u0432\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "-4:00" },
3140 { "bg", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u041a\\u0443\\u0431\\u0430", "America/Havana" },
3141 { "bg", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u041a\\u0443\\u0431\\u0438\\u043d\\u0441\\u043a\\u043e \\u0432\\u0440\\u0435\\u043C\\u0435", "America/Havana" },
3142
3143 { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3144 { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+11:00", "+11:00" },
3145 { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+11", "+11:00" },
3146 { "bg", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\\u0418\\u0437\\u0442\\u043E\\u0447\\u043D\\u043E\\u0430\\u0432\\u0441\\u0442\\u0440\\u0430\\u043B\\u0438\\u0439\\u0441\\u043A\\u043E \\u043B\\u044F\\u0442\\u043D\\u043E \\u0447\\u0430\\u0441\\u043E\\u0432\\u043E \\u0432\\u0440\\u0435\\u043C\\u0435", "+11:00" },
3147 { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3148 { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+10:00", "+10:00" },
3149 { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+10", "+10:00" },
3150 { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "\\u0418\\u0437\\u0442\\u043E\\u0447\\u043D\\u043E\\u0430\\u0432\\u0441\\u0442\\u0440\\u0430\\u043B\\u0438\\u0439\\u0441\\u043A\\u043E \\u0441\\u0442\\u0430\\u043D\\u0434\\u0430\\u0440\\u0442\\u043D\\u043E \\u0432\\u0440\\u0435\\u043C\\u0435", "+10:00" },
3151 { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u0421\\u0438\\u0434\\u043D\\u0438", "Australia/Sydney" },
3152 { "bg", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\\u0418\\u0437\\u0442\\u043E\\u0447\\u043D\\u043E\\u0430\\u0432\\u0441\\u0442\\u0440\\u0430\\u043B\\u0438\\u0439\\u0441\\u043A\\u043E \\u0432\\u0440\\u0435\\u043C\\u0435", "Australia/Sydney" },
3153
3154 { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3155 { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+11:00", "+11:00" },
3156 { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+11", "+11:00" },
3157 { "bg", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\\u0418\\u0437\\u0442\\u043E\\u0447\\u043D\\u043E\\u0430\\u0432\\u0441\\u0442\\u0440\\u0430\\u043B\\u0438\\u0439\\u0441\\u043A\\u043E \\u043B\\u044F\\u0442\\u043D\\u043E \\u0447\\u0430\\u0441\\u043E\\u0432\\u043E \\u0432\\u0440\\u0435\\u043C\\u0435", "+11:00" },
3158 { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3159 { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+10:00", "+10:00" },
3160 { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+10", "+10:00" },
3161 { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "\\u0418\\u0437\\u0442\\u043E\\u0447\\u043D\\u043E\\u0430\\u0432\\u0441\\u0442\\u0440\\u0430\\u043B\\u0438\\u0439\\u0441\\u043A\\u043E \\u0441\\u0442\\u0430\\u043D\\u0434\\u0430\\u0440\\u0442\\u043D\\u043E \\u0432\\u0440\\u0435\\u043C\\u0435", "+10:00" },
3162 { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u0421\\u0438\\u0434\\u043D\\u0438", "Australia/Sydney" },
3163 { "bg", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u0418\\u0437\\u0442\\u043E\\u0447\\u043D\\u043E\\u0430\\u0432\\u0441\\u0442\\u0440\\u0430\\u043B\\u0438\\u0439\\u0441\\u043A\\u043E \\u0432\\u0440\\u0435\\u043C\\u0435", "Australia/Sydney" },
3164
3165 { "bg", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
3166 { "bg", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447", "+0:00" },
3167 { "bg", "Europe/London", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447", "+0:00" },
3168 { "bg", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u0421\\u0440\\u0435\\u0434\\u043d\\u043e \\u0433\\u0440\\u0438\\u043d\\u0443\\u0438\\u0447\\u043a\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "+0:00" },
3169 { "bg", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
3170 { "bg", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+01:00", "+1:00" },
3171 { "bg", "Europe/London", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+1", "+1:00" },
3172 { "bg", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\\u0411\\u0440\\u0438\\u0442\\u0430\\u043d\\u0441\\u043a\\u043e \\u043b\\u044f\\u0442\\u043d\\u043e \\u0447\\u0430\\u0441\\u043e\\u0432\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "+1:00" },
3173 { "bg", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u041E\\u0431\\u0435\\u0434\\u0438\\u043D\\u0435\\u043D\\u043E\\u0442\\u043E \\u043A\\u0440\\u0430\\u043B\\u0441\\u0442\\u0432\\u043E", "Europe/London" },
3174 { "bg", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u041E\\u0431\\u0435\\u0434\\u0438\\u043D\\u0435\\u043D\\u043E\\u0442\\u043E \\u043A\\u0440\\u0430\\u043B\\u0441\\u0442\\u0432\\u043E", "Europe/London" },
3175
3176 { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3177 { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3178 { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3179 { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3180 { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3181 { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3182 { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3183 { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3184 { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-3", "-3:00" },
3185 { "bg", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
3186
3187 // JB#5150
3188 { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
3189 { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+05:30", "+5:30" },
3190 { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+5:30", "+5:30" },
3191 { "bg", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\\u0418\\u043D\\u0434\\u0438\\u0439\\u0441\\u043A\\u043E \\u0432\\u0440\\u0435\\u043c\\u0435", "+5:30" },
3192 { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
3193 { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+05:30", "+5:30" },
3194 { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+5:30", "+05:30" },
3195 { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\\u0418\\u043D\\u0434\\u0438\\u0439\\u0441\\u043A\\u043E \\u0432\\u0440\\u0435\\u043c\\u0435", "+5:30" },
3196 { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u0418\\u043D\\u0434\\u0438\\u044F", "Asia/Calcutta" },
3197 { "bg", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u0418\\u043D\\u0434\\u0438\\u0439\\u0441\\u043A\\u043E \\u0432\\u0440\\u0435\\u043c\\u0435", "Asia/Calcutta" },
3198 // ==========
3199
3200 { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
3201 { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
3202 { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "America/Los_Angeles" },
3203 { "ja", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "\\u30a2\\u30e1\\u30ea\\u30ab\\u592a\\u5e73\\u6d0b\\u6a19\\u6e96\\u6642", "America/Los_Angeles" },
3204 { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-700" },
3205 { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
3206 { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "America/Los_Angeles" },
3207 { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "\\u30a2\\u30e1\\u30ea\\u30ab\\u592a\\u5e73\\u6d0b\\u590f\\u6642\\u9593", "America/Los_Angeles" },
3208 // icu ja.txt has exemplar city for this time zone
3209 { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u30ED\\u30B5\\u30F3\\u30BC\\u30EB\\u30B9\\u6642\\u9593", "America/Los_Angeles" },
3210 { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\\u30A2\\u30E1\\u30EA\\u30AB\\u592A\\u5e73\\u6D0B\\u6642\\u9593", "America/Los_Angeles" },
3211 { "ja", "America/Los_Angeles", "2004-07-15T00:00:00Z", "VVVV", "\\u30ED\\u30B5\\u30F3\\u30BC\\u30EB\\u30B9\\u6642\\u9593", "America/Los_Angeles" },
3212
3213 { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3214 { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3215 { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3216 { "ja", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "-3:00" },
3217 { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3218 { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3219 { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3220 { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "-3:00" },
3221 // icu ja.txt does not have info for this time zone
3222 { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u30D6\\u30A8\\u30CE\\u30B9\\u30A2\\u30A4\\u30EC\\u30B9\\u6642\\u9593", "America/Buenos_Aires" },
3223 { "ja", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "America/Buenos_Aires" },
3224
3225 { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3226 { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3227 { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3228 { "ja", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "-3:00" },
3229 { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3230 { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3231 { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3232 { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "-3:00" },
3233 { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u30D6\\u30A8\\u30CE\\u30B9\\u30A2\\u30A4\\u30EC\\u30B9\\u6642\\u9593", "America/Buenos_Aires" },
3234 { "ja", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u30A2\\u30EB\\u30BC\\u30F3\\u30C1\\u30F3\\u6A19\\u6E96\\u6642", "America/Buenos_Aires" },
3235
3236 { "ja", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
3237 { "ja", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
3238 { "ja", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
3239 { "ja", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "\\u30AD\\u30E5\\u30FC\\u30D0\\u6A19\\u6E96\\u6642", "-5:00" },
3240 { "ja", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
3241 { "ja", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
3242 { "ja", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
3243 { "ja", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "\\u30AD\\u30E5\\u30FC\\u30D0\\u590F\\u6642\\u9593", "-4:00" },
3244 { "ja", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u30ad\\u30e5\\u30fc\\u30d0\\u6642\\u9593", "America/Havana" },
3245 { "ja", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u30ad\\u30e5\\u30fc\\u30d0\\u6642\\u9593", "America/Havana" },
3246
3247 { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3248 { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
3249 { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
3250 { "ja", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u590F\\u6642\\u9593", "+11:00" },
3251 { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3252 { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
3253 { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
3254 { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u6A19\\u6E96\\u6642", "+10:00" },
3255 // icu ja.txt does not have info for this time zone
3256 { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u30B7\\u30C9\\u30CB\\u30FC\\u6642\\u9593", "Australia/Sydney" },
3257 { "ja", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u6642\\u9593", "Australia/Sydney" },
3258
3259 { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3260 { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
3261 { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
3262 { "ja", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u590F\\u6642\\u9593", "+11:00" },
3263 { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3264 { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
3265 { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
3266 { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u6A19\\u6E96\\u6642", "+10:00" },
3267 { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u30B7\\u30C9\\u30CB\\u30FC\\u6642\\u9593", "Australia/Sydney" },
3268 { "ja", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u30AA\\u30FC\\u30B9\\u30C8\\u30E9\\u30EA\\u30A2\\u6771\\u90E8\\u6642\\u9593", "Australia/Sydney" },
3269
3270 { "ja", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
3271 { "ja", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
3272 { "ja", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
3273 { "ja", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "\\u30B0\\u30EA\\u30CB\\u30C3\\u30B8\\u6A19\\u6E96\\u6642", "+0:00" },
3274 { "ja", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
3275 { "ja", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
3276 { "ja", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
3277 { "ja", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\\u82f1\\u56fd\\u590f\\u6642\\u9593", "+1:00" },
3278 { "ja", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u30a4\\u30ae\\u30ea\\u30b9\\u6642\\u9593", "Europe/London" },
3279 { "ja", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u30a4\\u30ae\\u30ea\\u30b9\\u6642\\u9593", "Europe/London" },
3280 { "ja", "Europe/London", "2004-07-15T00:00:00Z", "VVVV", "\\u30a4\\u30ae\\u30ea\\u30b9\\u6642\\u9593", "Europe/London" },
3281
3282 { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3283 { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3284 { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3285 { "ja", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3286 { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3287 { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3288 { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3289 { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3290 { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
3291 { "ja", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
3292
3293 // JB#5150
3294 { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
3295 { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
3296 { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
3297 { "ja", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "\\u30A4\\u30F3\\u30C9\\u6A19\\u6E96\\u6642", "+5:30" },
3298 { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
3299 { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
3300 { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
3301 { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "\\u30A4\\u30F3\\u30C9\\u6A19\\u6E96\\u6642", "+5:30" },
3302 { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u30A4\\u30F3\\u30C9\\u6642\\u9593", "Asia/Calcutta" },
3303 { "ja", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u30A4\\u30F3\\u30C9\\u6A19\\u6E96\\u6642", "Asia/Calcutta" },
3304
3305 // ==========
3306
3307 { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "Z", "-0800", "-8:00" },
3308 { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-08:00", "-8:00" },
3309 { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "z", "GMT-8", "-8:00" },
3310 { "ti", "America/Los_Angeles", "2004-01-15T00:00:00Z", "zzzz", "GMT-08:00", "-8:00" },
3311 { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "Z", "-0700", "-7:00" },
3312 { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-07:00", "-7:00" },
3313 { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "z", "GMT-7", "-7:00" },
3314 { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "zzzz", "GMT-07:00", "-7:00" },
3315 { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "v", "\\u130D\\u12DC \\u120E\\u1235 \\u12A3\\u1295\\u1300\\u1208\\u1235", "America/Los_Angeles" },
3316 { "ti", "America/Los_Angeles", "2004-07-15T00:00:00Z", "vvvv", "\\u130D\\u12DC \\u120E\\u1235 \\u12A3\\u1295\\u1300\\u1208\\u1235", "America/Los_Angeles" },
3317
3318 { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3319 { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3320 { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3321 { "ti", "America/Argentina/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u121D\\u12F1\\u1265 \\u130D\\u12DC \\u12A3\\u122D\\u1300\\u1295\\u1272\\u1293", "-3:00" },
3322 { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3323 { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3324 { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3325 { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u121D\\u12F1\\u1265 \\u130D\\u12DC \\u12A3\\u122D\\u1300\\u1295\\u1272\\u1293", "-3:00" },
3326 { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u130D\\u12DC \\u1265\\u12C8\\u1296\\u1235 \\u12A3\\u12ED\\u1228\\u1235", "America/Buenos_Aires" },
3327 { "ti", "America/Argentina/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u121D\\u12F1\\u1265 \\u130D\\u12DC \\u12A3\\u122D\\u1300\\u1295\\u1272\\u1293", "America/Buenos_Aires" },
3328
3329 { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3330 { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3331 { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3332 { "ti", "America/Buenos_Aires", "2004-01-15T00:00:00Z", "zzzz", "\\u121D\\u12F1\\u1265 \\u130D\\u12DC \\u12A3\\u122D\\u1300\\u1295\\u1272\\u1293", "-3:00" },
3333 { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3334 { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3335 { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3336 { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "zzzz", "\\u121D\\u12F1\\u1265 \\u130D\\u12DC \\u12A3\\u122D\\u1300\\u1295\\u1272\\u1293", "-3:00" },
3337 { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "v", "\\u130D\\u12DC \\u1265\\u12C8\\u1296\\u1235 \\u12A3\\u12ED\\u1228\\u1235", "America/Buenos_Aires" },
3338 { "ti", "America/Buenos_Aires", "2004-07-15T00:00:00Z", "vvvv", "\\u121D\\u12F1\\u1265 \\u130D\\u12DC \\u12A3\\u122D\\u1300\\u1295\\u1272\\u1293", "America/Buenos_Aires" },
3339
3340 { "ti", "America/Havana", "2004-01-15T00:00:00Z", "Z", "-0500", "-5:00" },
3341 { "ti", "America/Havana", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-05:00", "-5:00" },
3342 { "ti", "America/Havana", "2004-01-15T00:00:00Z", "z", "GMT-5", "-5:00" },
3343 { "ti", "America/Havana", "2004-01-15T00:00:00Z", "zzzz", "GMT-05:00", "-5:00" },
3344 { "ti", "America/Havana", "2004-07-15T00:00:00Z", "Z", "-0400", "-4:00" },
3345 { "ti", "America/Havana", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-04:00", "-4:00" },
3346 { "ti", "America/Havana", "2004-07-15T00:00:00Z", "z", "GMT-4", "-4:00" },
3347 { "ti", "America/Havana", "2004-07-15T00:00:00Z", "zzzz", "GMT-04:00", "-4:00" },
3348 { "ti", "America/Havana", "2004-07-15T00:00:00Z", "v", "\\u130D\\u12DC \\u12A9\\u1263", "America/Havana" },
3349 { "ti", "America/Havana", "2004-07-15T00:00:00Z", "vvvv", "\\u130D\\u12DC \\u12A9\\u1263", "America/Havana" },
3350
3351 { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3352 { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
3353 { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
3354 { "ti", "Australia/ACT", "2004-01-15T00:00:00Z", "zzzz", "GMT+11:00", "+11:00" },
3355 { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3356 { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
3357 { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
3358 { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "zzzz", "GMT+10:00", "+10:00" },
3359 { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "v", "\\u130D\\u12DC \\u1232\\u12F5\\u1292", "Australia/Sydney" },
3360 { "ti", "Australia/ACT", "2004-07-15T00:00:00Z", "vvvv", "\\u130D\\u12DC \\u1232\\u12F5\\u1292", "Australia/Sydney" },
3361
3362 { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "Z", "+1100", "+11:00" },
3363 { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+11:00", "+11:00" },
3364 { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "z", "GMT+11", "+11:00" },
3365 { "ti", "Australia/Sydney", "2004-01-15T00:00:00Z", "zzzz", "GMT+11:00", "+11:00" },
3366 { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "Z", "+1000", "+10:00" },
3367 { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+10:00", "+10:00" },
3368 { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "z", "GMT+10", "+10:00" },
3369 { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "zzzz", "GMT+10:00", "+10:00" },
3370 { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "v", "\\u130D\\u12DC \\u1232\\u12F5\\u1292", "Australia/Sydney" },
3371 { "ti", "Australia/Sydney", "2004-07-15T00:00:00Z", "vvvv", "\\u130D\\u12DC \\u1232\\u12F5\\u1292", "Australia/Sydney" },
3372
3373 { "ti", "Europe/London", "2004-01-15T00:00:00Z", "Z", "+0000", "+0:00" },
3374 { "ti", "Europe/London", "2004-01-15T00:00:00Z", "ZZZZ", "GMT", "+0:00" },
3375 { "ti", "Europe/London", "2004-01-15T00:00:00Z", "z", "GMT", "+0:00" },
3376 { "ti", "Europe/London", "2004-01-15T00:00:00Z", "zzzz", "GMT", "+0:00" },
3377 { "ti", "Europe/London", "2004-07-15T00:00:00Z", "Z", "+0100", "+1:00" },
3378 { "ti", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+01:00", "+1:00" },
3379 { "ti", "Europe/London", "2004-07-15T00:00:00Z", "z", "GMT+1", "+1:00" },
3380 { "ti", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\\u130D\\u12DC \\u12AD\\u1228\\u121D\\u1272 \\u1265\\u122A\\u1323\\u1295\\u12EB", "+1:00" },
3381 { "ti", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u130D\\u12DC \\u1265\\u122A\\u1323\\u1295\\u12EB", "Europe/London" },
3382 { "ti", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u130D\\u12DC \\u1265\\u122A\\u1323\\u1295\\u12EB", "Europe/London" },
3383
3384 { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
3385 { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3386 { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3387 { "ti", "Etc/GMT+3", "2004-01-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3388 { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "Z", "-0300", "-3:00" },
3389 { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "ZZZZ", "GMT-03:00", "-3:00" },
3390 { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "z", "GMT-3", "-3:00" },
3391 { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "zzzz", "GMT-03:00", "-3:00" },
3392 { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "v", "GMT-3", "-3:00" },
3393 { "ti", "Etc/GMT+3", "2004-07-15T00:00:00Z", "vvvv", "GMT-03:00", "-3:00" },
3394
3395 // JB#5150
3396 { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "Z", "+0530", "+5:30" },
3397 { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
3398 { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "z", "GMT+5:30", "+5:30" },
3399 { "ti", "Asia/Calcutta", "2004-01-15T00:00:00Z", "zzzz", "GMT+05:30", "+5:30" },
3400 { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "Z", "+0530", "+5:30" },
3401 { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "ZZZZ", "GMT+05:30", "+5:30" },
3402 { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "z", "GMT+5:30", "+05:30" },
3403 { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "zzzz", "GMT+05:30", "+5:30" },
3404 { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "v", "\\u130D\\u12DC \\u1205\\u1295\\u12F2", "Alna/Calcutta" },
3405 { "ti", "Asia/Calcutta", "2004-07-15T00:00:00Z", "vvvv", "\\u130D\\u12DC \\u1205\\u1295\\u12F2", "Asia/Calcutta" },
3406
3407 // Ticket#8589 Partial location name to use country name if the zone is the golden
3408 // zone for the time zone's country.
3409 { "en_MX", "America/Chicago", "1995-07-15T00:00:00Z", "vvvv", "Central Time (United States)", "America/Chicago"},
3410
3411 // Tests proper handling of time zones that should have empty sets when inherited from the parent.
3412 // For example, en_GB understands CET as Central European Time, but en_HK, which inherits from en_GB
3413 // does not
3414 { "en_GB", "Europe/Paris", "2004-01-15T00:00:00Z", "zzzz", "Central European Standard Time", "+1:00"},
3415 { "en_GB", "Europe/Paris", "2004-07-15T00:00:00Z", "zzzz", "Central European Summer Time", "+2:00"},
3416 { "en_GB", "Europe/Paris", "2004-01-15T00:00:00Z", "z", "CET", "+1:00"},
3417 { "en_GB", "Europe/Paris", "2004-07-15T00:00:00Z", "z", "CEST", "+2:00"},
3418 { "en_HK", "Europe/Paris", "2004-01-15T00:00:00Z", "zzzz", "Central European Standard Time", "+1:00"},
3419 { "en_HK", "Europe/Paris", "2004-07-15T00:00:00Z", "zzzz", "Central European Summer Time", "+2:00"},
3420 { "en_HK", "Europe/Paris", "2004-01-15T00:00:00Z", "z", "GMT+1", "+1:00"},
3421 { "en_HK", "Europe/Paris", "2004-07-15T00:00:00Z", "z", "GMT+2", "+2:00"},
3422
3423 { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr },
3424 };
3425
3426 UErrorCode status = U_ZERO_ERROR;
3427 LocalPointer<Calendar> cal(GregorianCalendar::createInstance(status));
3428 if (failure(status, "GregorianCalendar::createInstance", true)) return;
3429 SimpleDateFormat testfmt(UnicodeString("yyyy-MM-dd'T'HH:mm:ss'Z'"), status);
3430 if (failure(status, "SimpleDateFormat constructor", true)) return;
3431 testfmt.setTimeZone(*TimeZone::getGMT());
3432
3433 for (int i = 0; fallbackTests[i][0]; i++) {
3434 const char **testLine = fallbackTests[i];
3435 UnicodeString info[5];
3436 for ( int j = 0 ; j < 5 ; j++ ) {
3437 info[j] = UnicodeString(testLine[j], -1, US_INV);
3438 }
3439 info[4] = info[4].unescape();
3440 logln("%s;%s;%s;%s", testLine[0], testLine[1], testLine[2], testLine[3]);
3441
3442 TimeZone *tz = TimeZone::createTimeZone(info[1]);
3443
3444 UDate d = testfmt.parse(testLine[2], status);
3445 cal->setTime(d, status);
3446 if (U_FAILURE(status)) {
3447 errln(UnicodeString("Failed to set date: ") + testLine[2]);
3448 }
3449
3450 SimpleDateFormat fmt(info[3], Locale(testLine[0]),status);
3451 ASSERT_OK(status);
3452 cal->adoptTimeZone(tz);
3453 UnicodeString result;
3454 FieldPosition pos(FieldPosition::DONT_CARE);
3455 fmt.format(*cal.getAlias(), result,pos);
3456 if (result != info[4]) {
3457 errln(info[0] + ";" + info[1] + ";" + info[2] + ";" + info[3] + " expected: '" +
3458 info[4] + "' but got: '" + result + "'");
3459 }
3460 }
3461 }
3462
TestTimeZoneInLocale()3463 void DateFormatTest::TestTimeZoneInLocale()
3464 {
3465 const char *tests[][3] = {
3466 { "en-u-tz-usden", "America/Denver", "gregorian" },
3467 { "es-u-tz-usden", "America/Denver", "gregorian" },
3468 { "ms-u-tz-mykul", "Asia/Kuala_Lumpur", "gregorian" },
3469 { "zh-u-tz-mykul", "Asia/Kuala_Lumpur", "gregorian" },
3470 { "fr-u-ca-buddhist-tz-phmnl", "Asia/Manila", "buddhist" },
3471 { "th-u-ca-chinese-tz-gblon", "Europe/London", "chinese" },
3472 { "de-u-ca-coptic-tz-ciabj", "Africa/Abidjan", "coptic" },
3473 { "ja-u-ca-dangi-tz-hkhkg", "Asia/Hong_Kong", "dangi" },
3474 { "da-u-ca-ethioaa-tz-ruunera", "Asia/Ust-Nera", "ethiopic-amete-alem" },
3475 { "ko-u-ca-ethiopic-tz-cvrai", "Atlantic/Cape_Verde", "ethiopic" },
3476 { "fil-u-ca-gregory-tz-aubne", "Australia/Brisbane", "gregorian" },
3477 { "fa-u-ca-hebrew-tz-brrbr", "America/Rio_Branco", "hebrew" },
3478 { "gr-u-ca-indian-tz-lccas", "America/St_Lucia", "indian" },
3479 { "or-u-ca-islamic-tz-cayyn", "America/Swift_Current", "islamic" },
3480 { "my-u-ca-islamic-umalqura-tz-kzala", "Asia/Almaty", "islamic-umalqura" },
3481 { "lo-u-ca-islamic-tbla-tz-bmbda", "Atlantic/Bermuda", "islamic-tbla" },
3482 { "km-u-ca-islamic-civil-tz-aqplm", "Antarctica/Palmer", "islamic-civil" },
3483 { "kk-u-ca-islamic-rgsa-tz-usanc", "America/Anchorage", "islamic-rgsa" },
3484 { "ar-u-ca-iso8601-tz-bjptn", "Africa/Porto-Novo", "iso8601" },
3485 { "he-u-ca-japanese-tz-tzdar", "Africa/Dar_es_Salaam", "japanese" },
3486 { "bs-u-ca-persian-tz-etadd", "Africa/Addis_Ababa", "persian" },
3487 { "it-u-ca-roc-tz-aruaq", "America/Argentina/San_Juan", "roc" },
3488 };
3489
3490 for (int32_t i = 0; i < UPRV_LENGTHOF(tests); ++i) {
3491 UErrorCode status = U_ZERO_ERROR;
3492 const char **testLine = tests[i];
3493 Locale locale(testLine[0]);
3494 UnicodeString expectedTimezone(testLine[1], -1, US_INV);
3495 UnicodeString actual;
3496
3497 SimpleDateFormat smptfmt("Z", locale, status);
3498 ASSERT_OK(status);
3499 assertEquals("TimeZone from SimpleDateFormat constructor",
3500 expectedTimezone, smptfmt.getTimeZone().getID(actual));
3501 assertEquals("Calendar from SimpleDateFormat constructor",
3502 testLine[2], smptfmt.getCalendar()->getType());
3503
3504 LocalPointer<DateFormat> datefmt(
3505 DateFormat::createDateInstance(DateFormat::kDefault, locale));
3506 if (datefmt == nullptr) {
3507 dataerrln("Error calling DateFormat::createDateInstance()");
3508 return;
3509 }
3510 assertEquals("TimeZone from DateFormat::createDateInstance",
3511 expectedTimezone, datefmt->getTimeZone().getID(actual));
3512 assertEquals("Calendar from DateFormat::createDateInstance",
3513 testLine[2], datefmt->getCalendar()->getType());
3514 LocalPointer<DateFormat> timefmt(
3515 DateFormat::createTimeInstance(DateFormat::kDefault, locale));
3516 if (timefmt == nullptr) {
3517 dataerrln("Error calling DateFormat::createTimeInstance()");
3518 return;
3519 }
3520 assertEquals("TimeZone from TimeFormat::createTimeInstance",
3521 expectedTimezone, timefmt->getTimeZone().getID(actual));
3522 assertEquals("Calendar from DateFormat::createTimeInstance",
3523 testLine[2], timefmt->getCalendar()->getType());
3524
3525 LocalPointer<DateFormat> datetimefmt(
3526 DateFormat::createDateTimeInstance(
3527 DateFormat::kDefault, DateFormat::kDefault, locale));
3528 if (datetimefmt == nullptr) {
3529 dataerrln("Error calling DateFormat::createDateTimeInstance()");
3530 return;
3531 }
3532 assertEquals("TimeZone from DateTimeFormat::createDateTimeInstance",
3533 expectedTimezone, datetimefmt->getTimeZone().getID(actual));
3534 assertEquals("Calendar from DateFormat::createDateTimeInstance",
3535 testLine[2], datetimefmt->getCalendar()->getType());
3536 }
3537 }
3538
TestRoundtripWithCalendar()3539 void DateFormatTest::TestRoundtripWithCalendar() {
3540 UErrorCode status = U_ZERO_ERROR;
3541
3542 TimeZone *tz = TimeZone::createTimeZone("Europe/Paris");
3543 TimeZone *gmt = TimeZone::createTimeZone("Etc/GMT");
3544
3545 Calendar *calendars[] = {
3546 Calendar::createInstance(*tz, Locale("und@calendar=gregorian"), status),
3547 Calendar::createInstance(*tz, Locale("und@calendar=buddhist"), status),
3548 // Calendar::createInstance(*tz, Locale("und@calendar=hebrew"), status),
3549 Calendar::createInstance(*tz, Locale("und@calendar=islamic"), status),
3550 Calendar::createInstance(*tz, Locale("und@calendar=japanese"), status),
3551 nullptr
3552 };
3553 if (U_FAILURE(status)) {
3554 dataerrln("Failed to initialize calendars: %s", u_errorName(status));
3555 for (int i = 0; calendars[i] != nullptr; i++) {
3556 delete calendars[i];
3557 }
3558 return;
3559 }
3560
3561 //FIXME The formatters commented out below are currently failing because of
3562 // the calendar calculation problem reported by #6691
3563
3564 // The order of test formatters must match the order of calendars above.
3565 DateFormat *formatters[] = {
3566 DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("en_US")), //calendar=gregorian
3567 DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("th_TH")), //calendar=buddhist
3568 // DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("he_IL@calendar=hebrew")),
3569 DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("ar_EG@calendar=islamic")),
3570 // DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("ja_JP@calendar=japanese")),
3571 nullptr
3572 };
3573
3574 UDate d = Calendar::getNow();
3575 UnicodeString buf;
3576 FieldPosition fpos;
3577 ParsePosition ppos;
3578
3579 for (int i = 0; formatters[i] != nullptr; i++) {
3580 buf.remove();
3581 fpos.setBeginIndex(0);
3582 fpos.setEndIndex(0);
3583 calendars[i]->setTime(d, status);
3584
3585 // Normal case output - the given calendar matches the calendar
3586 // used by the formatter
3587 formatters[i]->format(*calendars[i], buf, fpos);
3588 UnicodeString refStr(buf);
3589
3590 for (int j = 0; calendars[j] != nullptr; j++) {
3591 if (j == i) {
3592 continue;
3593 }
3594 buf.remove();
3595 fpos.setBeginIndex(0);
3596 fpos.setEndIndex(0);
3597 calendars[j]->setTime(d, status);
3598
3599 // Even the different calendar type is specified,
3600 // we should get the same result.
3601 formatters[i]->format(*calendars[j], buf, fpos);
3602 if (refStr != buf) {
3603 errln((UnicodeString)"FAIL: Different format result with a different calendar for the same time -"
3604 + "\n Reference calendar type=" + calendars[i]->getType()
3605 + "\n Another calendar type=" + calendars[j]->getType()
3606 + "\n Expected result=" + refStr
3607 + "\n Actual result=" + buf);
3608 }
3609 }
3610
3611 calendars[i]->setTimeZone(*gmt);
3612 calendars[i]->clear();
3613 ppos.setErrorIndex(-1);
3614 ppos.setIndex(0);
3615
3616 // Normal case parse result - the given calendar matches the calendar
3617 // used by the formatter
3618 formatters[i]->parse(refStr, *calendars[i], ppos);
3619
3620 for (int j = 0; calendars[j] != nullptr; j++) {
3621 if (j == i) {
3622 continue;
3623 }
3624 calendars[j]->setTimeZone(*gmt);
3625 calendars[j]->clear();
3626 ppos.setErrorIndex(-1);
3627 ppos.setIndex(0);
3628
3629 // Even the different calendar type is specified,
3630 // we should get the same time and time zone.
3631 formatters[i]->parse(refStr, *calendars[j], ppos);
3632 if (calendars[i]->getTime(status) != calendars[j]->getTime(status)
3633 || calendars[i]->getTimeZone() != calendars[j]->getTimeZone()) {
3634 UnicodeString tzid;
3635 errln((UnicodeString)"FAIL: Different parse result with a different calendar for the same string -"
3636 + "\n Reference calendar type=" + calendars[i]->getType()
3637 + "\n Another calendar type=" + calendars[j]->getType()
3638 + "\n Date string=" + refStr
3639 + "\n Expected time=" + calendars[i]->getTime(status)
3640 + "\n Expected time zone=" + calendars[i]->getTimeZone().getID(tzid)
3641 + "\n Actual time=" + calendars[j]->getTime(status)
3642 + "\n Actual time zone=" + calendars[j]->getTimeZone().getID(tzid));
3643 }
3644 }
3645 if (U_FAILURE(status)) {
3646 errln((UnicodeString)"FAIL: " + u_errorName(status));
3647 break;
3648 }
3649 }
3650
3651 delete tz;
3652 delete gmt;
3653 for (int i = 0; calendars[i] != nullptr; i++) {
3654 delete calendars[i];
3655 }
3656 for (int i = 0; formatters[i] != nullptr; i++) {
3657 delete formatters[i];
3658 }
3659 }
3660
3661 /*
3662 void DateFormatTest::TestRelativeError()
3663 {
3664 UErrorCode status;
3665 Locale en("en");
3666
3667 DateFormat *en_reltime_reldate = DateFormat::createDateTimeInstance(DateFormat::kFullRelative,DateFormat::kFullRelative,en);
3668 if(en_reltime_reldate == nullptr) {
3669 logln("PASS: rel date/rel time failed");
3670 } else {
3671 errln("FAIL: rel date/rel time created, should have failed.");
3672 delete en_reltime_reldate;
3673 }
3674 }
3675
3676 void DateFormatTest::TestRelativeOther()
3677 {
3678 logln("Nothing in this test. When we get more data from CLDR, put in some tests of -2, +2, etc. ");
3679 }
3680 */
3681
Test6338()3682 void DateFormatTest::Test6338()
3683 {
3684 UErrorCode status = U_ZERO_ERROR;
3685
3686 SimpleDateFormat fmt1(UnicodeString(u"y-M-d"), Locale("ar"), status);
3687 if (failure(status, "new SimpleDateFormat", true)) return;
3688
3689 UDate dt1 = date(2008-1900, UCAL_JUNE, 10, 12, 00);
3690 UnicodeString str1;
3691 str1 = fmt1.format(dt1, str1);
3692 logln(str1);
3693
3694 UDate dt11 = fmt1.parse(str1, status);
3695 failure(status, "fmt->parse");
3696
3697 UnicodeString str11;
3698 str11 = fmt1.format(dt11, str11);
3699 logln(str11);
3700
3701 if (str1 != str11) {
3702 errln((UnicodeString)"FAIL: Different dates str1:" + str1
3703 + " str2:" + str11);
3704 }
3705
3706 /////////////////
3707
3708 status = U_ZERO_ERROR;
3709 SimpleDateFormat fmt2(UnicodeString(u"y M d"), Locale("ar"), status);
3710 failure(status, "new SimpleDateFormat");
3711
3712 UDate dt2 = date(2008-1900, UCAL_JUNE, 10, 12, 00);
3713 UnicodeString str2;
3714 str2 = fmt2.format(dt2, str2);
3715 logln(str2);
3716
3717 UDate dt22 = fmt2.parse(str2, status);
3718 failure(status, "fmt->parse");
3719
3720 UnicodeString str22;
3721 str22 = fmt2.format(dt22, str22);
3722 logln(str22);
3723
3724 if (str2 != str22) {
3725 errln((UnicodeString)"FAIL: Different dates str1:" + str2
3726 + " str2:" + str22);
3727 }
3728
3729 /////////////////
3730
3731 status = U_ZERO_ERROR;
3732 SimpleDateFormat fmt3(UnicodeString("y-M-d"), Locale("en-us"), status);
3733 failure(status, "new SimpleDateFormat");
3734
3735 UDate dt3 = date(2008-1900, UCAL_JUNE, 10, 12, 00);
3736 UnicodeString str3;
3737 str3 = fmt3.format(dt3, str3);
3738 logln(str3);
3739
3740 UDate dt33 = fmt3.parse(str3, status);
3741 failure(status, "fmt->parse");
3742
3743 UnicodeString str33;
3744 str33 = fmt3.format(dt33, str33);
3745 logln(str33);
3746
3747 if (str3 != str33) {
3748 errln((UnicodeString)"FAIL: Different dates str1:" + str3
3749 + " str2:" + str33);
3750 }
3751
3752 /////////////////
3753
3754 status = U_ZERO_ERROR;
3755 SimpleDateFormat fmt4(UnicodeString("y M d"), Locale("en-us"), status);
3756 failure(status, "new SimpleDateFormat");
3757
3758 UDate dt4 = date(2008-1900, UCAL_JUNE, 10, 12, 00);
3759 UnicodeString str4;
3760 str4 = fmt4.format(dt4, str4);
3761 logln(str4);
3762
3763 UDate dt44 = fmt4.parse(str4, status);
3764 failure(status, "fmt->parse");
3765
3766 UnicodeString str44;
3767 str44 = fmt4.format(dt44, str44);
3768 logln(str44);
3769
3770 if (str4 != str44) {
3771 errln((UnicodeString)"FAIL: Different dates str1:" + str4
3772 + " str2:" + str44);
3773 }
3774
3775 }
3776
Test6726()3777 void DateFormatTest::Test6726()
3778 {
3779 // status
3780 // UErrorCode status = U_ZERO_ERROR;
3781
3782 // fmtf, fmtl, fmtm, fmts;
3783 UnicodeString strf, strl, strm, strs;
3784 UDate dt = date(2008-1900, UCAL_JUNE, 10, 12, 00);
3785
3786 Locale loc("ja");
3787 DateFormat* fmtf = DateFormat::createDateTimeInstance(DateFormat::FULL, DateFormat::FULL, loc);
3788 DateFormat* fmtl = DateFormat::createDateTimeInstance(DateFormat::LONG, DateFormat::FULL, loc);
3789 DateFormat* fmtm = DateFormat::createDateTimeInstance(DateFormat::MEDIUM, DateFormat::FULL, loc);
3790 DateFormat* fmts = DateFormat::createDateTimeInstance(DateFormat::SHORT, DateFormat::FULL, loc);
3791 if (fmtf == nullptr || fmtl == nullptr || fmtm == nullptr || fmts == nullptr) {
3792 dataerrln("Unable to create DateFormat. got nullptr.");
3793 /* It may not be true that if one is nullptr all is nullptr. Just to be safe. */
3794 delete fmtf;
3795 delete fmtl;
3796 delete fmtm;
3797 delete fmts;
3798
3799 return;
3800 }
3801 strf = fmtf->format(dt, strf);
3802 strl = fmtl->format(dt, strl);
3803 strm = fmtm->format(dt, strm);
3804 strs = fmts->format(dt, strs);
3805
3806
3807 logln("strm.charAt(10)=%04X wanted 0x20\n", strm.charAt(10));
3808 if (strm.charAt(10) != char16_t(0x0020)) {
3809 errln((UnicodeString)"FAIL: Improper formatted date: " + strm );
3810 }
3811 logln("strs.charAt(10)=%04X wanted 0x20\n", strs.charAt(8));
3812 if (strs.charAt(10) != char16_t(0x0020)) {
3813 errln((UnicodeString)"FAIL: Improper formatted date: " + strs);
3814 }
3815
3816 delete fmtf;
3817 delete fmtl;
3818 delete fmtm;
3819 delete fmts;
3820
3821 return;
3822 }
3823
3824 /**
3825 * Test DateFormat's parsing of default GMT variants. See ticket#6135
3826 */
TestGMTParsing()3827 void DateFormatTest::TestGMTParsing() {
3828 const char* DATA[] = {
3829 "HH:mm:ss Z",
3830
3831 // pattern, input, expected output (in quotes)
3832 "HH:mm:ss Z", "10:20:30 GMT+03:00", "10:20:30 +0300",
3833 "HH:mm:ss Z", "10:20:30 UT-02:00", "10:20:30 -0200",
3834 "HH:mm:ss Z", "10:20:30 GMT", "10:20:30 +0000",
3835 "HH:mm:ss vvvv", "10:20:30 UT+10:00", "10:20:30 +1000",
3836 "HH:mm:ss zzzz", "10:20:30 UTC", "10:20:30 +0000", // standalone "UTC"
3837 "ZZZZ HH:mm:ss", "UT 10:20:30", "10:20:30 +0000",
3838 "z HH:mm:ss", "UT+0130 10:20:30", "10:20:30 +0130",
3839 "z HH:mm:ss", "UTC+0130 10:20:30", "10:20:30 +0130",
3840 // Note: GMT-1100 no longer works because of the introduction of the short
3841 // localized GMT support. Previous implementation support this level of
3842 // leniency (no separator char in localized GMT format), but the new
3843 // implementation handles GMT-11 as the legitimate short localized GMT format
3844 // and stop at there. Otherwise, roundtrip would be broken.
3845 //"HH mm Z ss", "10 20 GMT-1100 30", "10:20:30 -1100",
3846 "HH mm Z ss", "10 20 GMT-11 30", "10:20:30 -1100",
3847 "HH:mm:ssZZZZZ", "14:25:45Z", "14:25:45 +0000",
3848 "HH:mm:ssZZZZZ", "15:00:00-08:00", "15:00:00 -0800",
3849 };
3850 const int32_t DATA_len = UPRV_LENGTHOF(DATA);
3851 expectParse(DATA, DATA_len, Locale("en"));
3852 }
3853
3854 // Test case for localized GMT format parsing
3855 // with no delimitters in offset format (Chinese locale)
Test6880()3856 void DateFormatTest::Test6880() {
3857 UErrorCode status = U_ZERO_ERROR;
3858 UDate d1, d2, dp1, dp2, dexp1, dexp2;
3859 UnicodeString s1, s2;
3860
3861 TimeZone *tz = TimeZone::createTimeZone("Asia/Shanghai");
3862 GregorianCalendar gcal(*tz, status);
3863 if (failure(status, "construct GregorianCalendar", true)) return;
3864
3865 gcal.clear();
3866 gcal.set(1900, UCAL_JULY, 1, 12, 00); // offset 8:05:43
3867 d1 = gcal.getTime(status);
3868
3869 gcal.clear();
3870 gcal.set(1950, UCAL_JULY, 1, 12, 00); // offset 8:00
3871 d2 = gcal.getTime(status);
3872
3873 gcal.clear();
3874 gcal.set(1970, UCAL_JANUARY, 1, 12, 00);
3875 dexp2 = gcal.getTime(status);
3876 dexp1 = dexp2 - (5*60 + 43)*1000; // subtract 5m43s
3877
3878 if (U_FAILURE(status)) {
3879 errln("FAIL: Gregorian calendar error");
3880 }
3881
3882 DateFormat *fmt = DateFormat::createTimeInstance(DateFormat::kFull, Locale("zh"));
3883 if (fmt == nullptr) {
3884 dataerrln("Unable to create DateFormat. Got nullptr.");
3885 return;
3886 }
3887 fmt->adoptTimeZone(tz);
3888
3889 fmt->format(d1, s1);
3890 fmt->format(d2, s2);
3891
3892 dp1 = fmt->parse(s1, status);
3893 dp2 = fmt->parse(s2, status);
3894
3895 if (U_FAILURE(status)) {
3896 errln("FAIL: Parse failure");
3897 }
3898
3899 if (dp1 != dexp1) {
3900 errln("FAIL: Failed to parse " + s1 + " parsed: " + dp1 + " expected: " + dexp1);
3901 }
3902 if (dp2 != dexp2) {
3903 errln("FAIL: Failed to parse " + s2 + " parsed: " + dp2 + " expected: " + dexp2);
3904 }
3905
3906 delete fmt;
3907 }
3908
3909 typedef struct {
3910 const char * localeStr;
3911 UBool lenient;
3912 UBool expectFail;
3913 UnicodeString datePattern;
3914 UnicodeString dateString;
3915 } NumAsStringItem;
3916
TestNumberAsStringParsing()3917 void DateFormatTest::TestNumberAsStringParsing()
3918 {
3919 const NumAsStringItem items[] = {
3920 // loc lenient fail? datePattern dateString
3921 { "", false, true, UnicodeString("y MMMM d HH:mm:ss"), UnicodeString("2009 7 14 08:43:57") },
3922 { "", true, false, UnicodeString("y MMMM d HH:mm:ss"), UnicodeString("2009 7 14 08:43:57") },
3923 { "en", false, false, UnicodeString("MMM d, y"), UnicodeString("Jul 14, 2009") },
3924 { "en", true, false, UnicodeString("MMM d, y"), UnicodeString("Jul 14, 2009") },
3925 { "en", false, true, UnicodeString("MMM d, y"), UnicodeString("7 14, 2009") },
3926 { "en", true, false, UnicodeString("MMM d, y"), UnicodeString("7 14, 2009") },
3927 { "ja", false, false, UnicodeString("yyyy/MM/dd"), UnicodeString("2009/07/14") },
3928 { "ja", true, false, UnicodeString("yyyy/MM/dd"), UnicodeString("2009/07/14") },
3929 //{ "ja", false, false, UnicodeString("yyyy/MMMMM/d"), UnicodeString("2009/7/14") }, // #8860 covers test failure
3930 { "ja", true, false, UnicodeString("yyyy/MMMMM/d"), UnicodeString("2009/7/14") },
3931 { "ja", false, false, CharsToUnicodeString("y\\u5E74M\\u6708d\\u65E5"), CharsToUnicodeString("2009\\u5E747\\u670814\\u65E5") },
3932 { "ja", true, false, CharsToUnicodeString("y\\u5E74M\\u6708d\\u65E5"), CharsToUnicodeString("2009\\u5E747\\u670814\\u65E5") },
3933 { "ja", false, false, CharsToUnicodeString("y\\u5E74MMMd\\u65E5"), CharsToUnicodeString("2009\\u5E747\\u670814\\u65E5") },
3934 { "ja", true, false, CharsToUnicodeString("y\\u5E74MMMd\\u65E5"), CharsToUnicodeString("2009\\u5E747\\u670814\\u65E5") }, // #8820 fixes test failure
3935 { "ko", false, false, UnicodeString("yyyy. M. d."), UnicodeString("2009. 7. 14.") },
3936 { "ko", true, false, UnicodeString("yyyy. M. d."), UnicodeString("2009. 7. 14.") },
3937 { "ko", false, false, UnicodeString("yyyy. MMMMM d."), CharsToUnicodeString("2009. 7\\uC6D4 14.") },
3938 { "ko", true, false, UnicodeString("yyyy. MMMMM d."), CharsToUnicodeString("2009. 7\\uC6D4 14.") }, // #8820 fixes test failure
3939 { "ko", false, false, CharsToUnicodeString("y\\uB144 M\\uC6D4 d\\uC77C"), CharsToUnicodeString("2009\\uB144 7\\uC6D4 14\\uC77C") },
3940 { "ko", true, false, CharsToUnicodeString("y\\uB144 M\\uC6D4 d\\uC77C"), CharsToUnicodeString("2009\\uB144 7\\uC6D4 14\\uC77C") },
3941 { "ko", false, false, CharsToUnicodeString("y\\uB144 MMM d\\uC77C"), CharsToUnicodeString("2009\\uB144 7\\uC6D4 14\\uC77C") },
3942 { "ko", true, false, CharsToUnicodeString("y\\uB144 MMM d\\uC77C"), CharsToUnicodeString("2009\\uB144 7\\uC6D4 14\\uC77C") }, // #8820 fixes test failure
3943 { nullptr, false, false, UnicodeString(""), UnicodeString("") }
3944 };
3945 const NumAsStringItem * itemPtr;
3946 for (itemPtr = items; itemPtr->localeStr != nullptr; itemPtr++ ) {
3947 Locale locale = Locale::createFromName(itemPtr->localeStr);
3948 UErrorCode status = U_ZERO_ERROR;
3949 SimpleDateFormat formatter(itemPtr->datePattern, locale, status);
3950 if (U_FAILURE(status)) {
3951 dataerrln("Unable to create SimpleDateFormat - %s", u_errorName(status));
3952 return;
3953 }
3954
3955 formatter.setLenient(itemPtr->lenient);
3956 formatter.setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, itemPtr->lenient, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, itemPtr->lenient, status);
3957 UDate date1 = formatter.parse(itemPtr->dateString, status);
3958 if (U_FAILURE(status)) {
3959 if (!itemPtr->expectFail) {
3960 errln("FAIL, err when expected success: Locale \"" + UnicodeString(itemPtr->localeStr) + "\", lenient " + itemPtr->lenient +
3961 ": using pattern \"" + itemPtr->datePattern + "\", could not parse \"" + itemPtr->dateString + "\"; err: " + u_errorName(status) );
3962 }
3963 } else if (itemPtr->expectFail) {
3964 errln("FAIL, expected err but got none: Locale \"" + UnicodeString(itemPtr->localeStr) + "\", lenient " + itemPtr->lenient +
3965 ": using pattern \"" + itemPtr->datePattern + "\", did parse \"" + itemPtr->dateString + "\"." );
3966 } else if (!itemPtr->lenient) {
3967 UnicodeString formatted;
3968 formatter.format(date1, formatted);
3969 if (formatted != itemPtr->dateString) {
3970 errln("FAIL, mismatch formatting parsed date: Locale \"" + UnicodeString(itemPtr->localeStr) + "\", lenient " + itemPtr->lenient +
3971 ": using pattern \"" + itemPtr->datePattern + "\", did parse \"" + itemPtr->dateString + "\", formatted result \"" + formatted + "\".");
3972 }
3973 }
3974 }
3975 }
3976
TestISOEra()3977 void DateFormatTest::TestISOEra() {
3978
3979 const char* data[] = {
3980 // input, output
3981 "BC 4004-10-23T07:00:00Z", "BC 4004-10-23T07:00:00Z",
3982 "AD 4004-10-23T07:00:00Z", "AD 4004-10-23T07:00:00Z",
3983 "-4004-10-23T07:00:00Z" , "BC 4005-10-23T07:00:00Z",
3984 "4004-10-23T07:00:00Z" , "AD 4004-10-23T07:00:00Z",
3985 };
3986
3987 int32_t numData = 8;
3988
3989 UErrorCode status = U_ZERO_ERROR;
3990
3991 // create formatter
3992 SimpleDateFormat *fmt1 = new SimpleDateFormat(UnicodeString("GGG yyyy-MM-dd'T'HH:mm:ss'Z"), status);
3993 failure(status, "new SimpleDateFormat", true);
3994 if (status == U_MISSING_RESOURCE_ERROR) {
3995 if (fmt1 != nullptr) {
3996 delete fmt1;
3997 }
3998 return;
3999 }
4000 for(int i=0; i < numData; i+=2) {
4001 // create input string
4002 UnicodeString in = data[i];
4003
4004 // parse string to date
4005 UDate dt1 = fmt1->parse(in, status);
4006 failure(status, "fmt->parse", true);
4007
4008 // format date back to string
4009 UnicodeString out;
4010 out = fmt1->format(dt1, out);
4011 logln(out);
4012
4013 // check that roundtrip worked as expected
4014 UnicodeString expected = data[i+1];
4015 if (out != expected) {
4016 dataerrln((UnicodeString)"FAIL: " + in + " -> " + out + " expected -> " + expected);
4017 }
4018 }
4019
4020 delete fmt1;
4021 }
TestFormalChineseDate()4022 void DateFormatTest::TestFormalChineseDate() {
4023
4024 UErrorCode status = U_ZERO_ERROR;
4025 UnicodeString pattern(u"y\u5e74M\u6708d\u65e5");
4026 UnicodeString numsys_override(u"y=hanidec;M=hans;d=hans");
4027
4028 // create formatter
4029 SimpleDateFormat sdf(pattern, numsys_override, Locale::getChina(),status);
4030 if (failure(status, "new SimpleDateFormat with override", true)) {
4031 return;
4032 }
4033
4034 UDate thedate = date(2009-1900, UCAL_JULY, 28);
4035 FieldPosition pos(FieldPosition::DONT_CARE);
4036 UnicodeString result;
4037 sdf.format(thedate,result,pos);
4038
4039 UnicodeString expected = "\\u4e8c\\u3007\\u3007\\u4e5d\\u5e74\\u4e03\\u6708\\u4e8c\\u5341\\u516b\\u65e5";
4040 expected = expected.unescape();
4041 if (result != expected) {
4042 dataerrln((UnicodeString)"FAIL: -> " + result + " expected -> " + expected);
4043 }
4044
4045 UDate parsedate = sdf.parse(expected,status);
4046 if ( parsedate != thedate ) {
4047 UnicodeString pat1 ("yyyy-MM-dd'T'HH:mm:ss'Z'", -1, US_INV );
4048 SimpleDateFormat usf(pat1, Locale::getEnglish(), status);
4049 UnicodeString parsedres,expres;
4050 usf.format(parsedate,parsedres,pos);
4051 usf.format(thedate,expres,pos);
4052 dataerrln((UnicodeString)"FAIL: parsed -> " + parsedres + " expected -> " + expres);
4053 }
4054 }
4055
4056 // Test case for #8675
4057 // Incorrect parse offset with stand alone GMT string on 2nd or later iteration.
TestStandAloneGMTParse()4058 void DateFormatTest::TestStandAloneGMTParse() {
4059 UErrorCode status = U_ZERO_ERROR;
4060 SimpleDateFormat sdf("ZZZZ", Locale(""), status);
4061
4062 if (U_SUCCESS(status)) {
4063
4064 UnicodeString inText(u"GMT$$$");
4065 for (int32_t i = 0; i < 10; i++) {
4066 ParsePosition pos(0);
4067 sdf.parse(inText, pos);
4068 if (pos.getIndex() != 3) {
4069 errln((UnicodeString)"FAIL: Incorrect output parse position: actual=" + pos.getIndex() + " expected=3");
4070 }
4071 }
4072
4073 } else {
4074 dataerrln("Unable to create SimpleDateFormat - %s", u_errorName(status));
4075 }
4076 }
4077
TestParsePosition()4078 void DateFormatTest::TestParsePosition() {
4079 const char* TestData[][4] = {
4080 // {<pattern>, <lead>, <date string>, <trail>}
4081 {"yyyy-MM-dd HH:mm:ssZ", "", "2010-01-10 12:30:00+0500", ""},
4082 {"yyyy-MM-dd HH:mm:ss ZZZZ", "", "2010-01-10 12:30:00 GMT+05:00", ""},
4083 {"Z HH:mm:ss", "", "-0100 13:20:30", ""},
4084 {"y-M-d Z", "", "2011-8-25 -0400", " Foo"},
4085 {"y/M/d H:mm:ss z", "", "2011/7/1 12:34:00 PDT", ""},
4086 {"y/M/d H:mm:ss z", "+123", "2011/7/1 12:34:00 PDT", " PST"},
4087 {"vvvv a h:mm:ss", "", "Pacific Time AM 10:21:45", ""},
4088 {"HH:mm v M/d", "111", "14:15 PT 8/10", " 12345"},
4089 {"'time zone:' VVVV 'date:' yyyy-MM-dd", "xxxx", "time zone: Los Angeles Time date: 2010-02-25", "xxxx"},
4090 {"yG", "", "2012AD", ""},
4091 {"yG", "", "2012", "x"},
4092 {0, 0, 0, 0},
4093 };
4094
4095 for (int32_t i = 0; TestData[i][0]; i++) {
4096 UErrorCode status = U_ZERO_ERROR;
4097 SimpleDateFormat sdf(UnicodeString(TestData[i][0]), status);
4098 if (failure(status, "new SimpleDateFormat", true)) return;
4099
4100 int32_t startPos, resPos;
4101
4102 // lead text
4103 UnicodeString input(TestData[i][1]);
4104 startPos = input.length();
4105
4106 // date string
4107 input += TestData[i][2];
4108 resPos = input.length();
4109
4110 // trail text
4111 input += TestData[i][3];
4112
4113 ParsePosition pos(startPos);
4114 //UDate d = sdf->parse(input, pos);
4115 (void)sdf.parse(input, pos);
4116
4117 if (pos.getIndex() != resPos) {
4118 errln(UnicodeString("FAIL: Parsing [") + input + "] with pattern [" + TestData[i][0] + "] returns position - "
4119 + pos.getIndex() + ", expected - " + resPos);
4120 }
4121 }
4122 }
4123
4124
4125 typedef struct {
4126 int32_t era;
4127 int32_t year;
4128 int32_t month; // 1-based
4129 int32_t isLeapMonth;
4130 int32_t day;
4131 } ChineseCalTestDate;
4132
4133 #define NUM_TEST_DATES 3
4134
4135 typedef struct {
4136 const char * locale;
4137 int32_t style; // <0 => custom
4138 UnicodeString dateString[NUM_TEST_DATES];
4139 } MonthPatternItem;
4140
TestMonthPatterns()4141 void DateFormatTest::TestMonthPatterns()
4142 {
4143 const ChineseCalTestDate dates[NUM_TEST_DATES] = {
4144 // era yr mo lp da
4145 { 78, 29, 4, 0, 2 }, // (in chinese era 78) gregorian 2012-4-22
4146 { 78, 29, 4, 1, 2 }, // (in chinese era 78) gregorian 2012-5-22
4147 { 78, 29, 5, 0, 2 }, // (in chinese era 78) gregorian 2012-6-20
4148 };
4149
4150 const MonthPatternItem items[] = {
4151 // locale date style; expected formats for the 3 dates above
4152 { "root@calendar=chinese", DateFormat::kLong, { UnicodeString("2012(ren-chen) M04 2"), UnicodeString("2012(ren-chen) M04bis 2"), UnicodeString("2012(ren-chen) M05 2") } },
4153 { "root@calendar=chinese", DateFormat::kShort, { UnicodeString("2012-04-02"), UnicodeString("2012-04bis-02"), UnicodeString("2012-05-02") } },
4154 { "root@calendar=chinese", -1, { UnicodeString("29-4-2"), UnicodeString("29-4bis-2"), UnicodeString("29-5-2") } },
4155 { "root@calendar=chinese", -2, { UnicodeString("78x29-4-2"), UnicodeString("78x29-4bis-2"), UnicodeString("78x29-5-2") } },
4156 { "root@calendar=chinese", -3, { UnicodeString("ren-chen-4-2"), UnicodeString("ren-chen-4bis-2"), UnicodeString("ren-chen-5-2") } },
4157 { "root@calendar=chinese", -4, { UnicodeString("ren-chen M04 2"), UnicodeString("ren-chen M04bis 2"), UnicodeString("ren-chen M05 2") } },
4158 { "en@calendar=gregorian", -3, { UnicodeString("2012-4-22"), UnicodeString("2012-5-22"), UnicodeString("2012-6-20") } },
4159 { "en@calendar=chinese", DateFormat::kLong, { UnicodeString("Fourth Month 2, 2012(ren-chen)"), UnicodeString("Fourth Monthbis 2, 2012(ren-chen)"), UnicodeString("Fifth Month 2, 2012(ren-chen)") } },
4160 { "en@calendar=chinese", DateFormat::kShort, { UnicodeString("4/2/2012"), UnicodeString("4bis/2/2012"), UnicodeString("5/2/2012") } },
4161 { "zh@calendar=chinese", DateFormat::kLong, { CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u56DB\\u6708\\u521D\\u4E8C"),
4162 CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u95F0\\u56DB\\u6708\\u521D\\u4E8C"),
4163 CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u4E94\\u6708\\u521D\\u4E8C") } },
4164 { "zh@calendar=chinese", DateFormat::kShort, { CharsToUnicodeString("2012/4/2"),
4165 CharsToUnicodeString("2012/\\u95F04/2"),
4166 CharsToUnicodeString("2012/5/2") } },
4167 { "zh@calendar=chinese", -3, { CharsToUnicodeString("\\u58EC\\u8FB0-4-2"),
4168 CharsToUnicodeString("\\u58EC\\u8FB0-\\u95F04-2"),
4169 CharsToUnicodeString("\\u58EC\\u8FB0-5-2") } },
4170 { "zh@calendar=chinese", -4, { CharsToUnicodeString("\\u58EC\\u8FB0 \\u56DB\\u6708 2"),
4171 CharsToUnicodeString("\\u58EC\\u8FB0 \\u95F0\\u56DB\\u6708 2"),
4172 CharsToUnicodeString("\\u58EC\\u8FB0 \\u4E94\\u6708 2") } },
4173 { "zh_Hant@calendar=chinese", DateFormat::kLong, { CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u56DB\\u6708\\u521D\\u4E8C"),
4174 CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u958F\\u56DB\\u6708\\u521D\\u4E8C"),
4175 CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u4E94\\u6708\\u521D\\u4E8C") } },
4176 { "zh_Hant@calendar=chinese", DateFormat::kShort, { CharsToUnicodeString("2012/4/2"),
4177 CharsToUnicodeString("2012/\\u958F4/2"),
4178 CharsToUnicodeString("2012/5/2") } },
4179 { "fr@calendar=chinese", DateFormat::kLong, { CharsToUnicodeString("2 s\\u00ECyu\\u00E8 ren-chen"),
4180 CharsToUnicodeString("2 s\\u00ECyu\\u00E8bis ren-chen"),
4181 CharsToUnicodeString("2 w\\u01D4yu\\u00E8 ren-chen") } },
4182 { "fr@calendar=chinese", DateFormat::kShort, { UnicodeString("2/4/29"), UnicodeString("2/4bis/29"), UnicodeString("2/5/29") } },
4183 { "en@calendar=dangi", DateFormat::kLong, { UnicodeString("Third Monthbis 2, 2012(ren-chen)"), UnicodeString("Fourth Month 2, 2012(ren-chen)"), UnicodeString("Fifth Month 1, 2012(ren-chen)") } },
4184 { "en@calendar=dangi", DateFormat::kShort, { UnicodeString("3bis/2/2012"), UnicodeString("4/2/2012"), UnicodeString("5/1/2012") } },
4185 { "en@calendar=dangi", -2, { UnicodeString("78x29-3bis-2"), UnicodeString("78x29-4-2"), UnicodeString("78x29-5-1") } },
4186 { "ko@calendar=dangi", DateFormat::kLong, { CharsToUnicodeString("\\uC784\\uC9C4\\uB144 \\uC7243\\uC6D4 2\\uC77C"),
4187 CharsToUnicodeString("\\uC784\\uC9C4\\uB144 4\\uC6D4 2\\uC77C"),
4188 CharsToUnicodeString("\\uC784\\uC9C4\\uB144 5\\uC6D4 1\\uC77C") } },
4189 { "ko@calendar=dangi", DateFormat::kShort, { CharsToUnicodeString("29. \\uC7243. 2."),
4190 CharsToUnicodeString("29. 4. 2."),
4191 CharsToUnicodeString("29. 5. 1.") } },
4192 // terminator
4193 { nullptr, 0, { UnicodeString(""), UnicodeString(""), UnicodeString("") } }
4194 };
4195
4196 //. style: -1 -2 -3 -4
4197 const UnicodeString customPatterns[] = { "y-Ml-d", "G'x'y-Ml-d", "U-M-d", "U MMM d" }; // like old root pattern, using 'l'
4198
4199 UErrorCode status = U_ZERO_ERROR;
4200 Locale rootChineseCalLocale = Locale::createFromName("root@calendar=chinese");
4201 Calendar * rootChineseCalendar = Calendar::createInstance(rootChineseCalLocale, status);
4202 if (U_SUCCESS(status)) {
4203 const MonthPatternItem * itemPtr;
4204 for (itemPtr = items; itemPtr->locale != nullptr; itemPtr++ ) {
4205 Locale locale = Locale::createFromName(itemPtr->locale);
4206 DateFormat * dmft = (itemPtr->style >= 0)?
4207 DateFormat::createDateInstance((DateFormat::EStyle)itemPtr->style, locale):
4208 new SimpleDateFormat(customPatterns[-itemPtr->style - 1], locale, status);
4209 if ( dmft != nullptr ) {
4210 if (U_SUCCESS(status)) {
4211 const ChineseCalTestDate * datePtr = dates;
4212 int32_t idate;
4213 for (idate = 0; idate < NUM_TEST_DATES; idate++, datePtr++) {
4214 rootChineseCalendar->clear();
4215 rootChineseCalendar->set(UCAL_ERA, datePtr->era);
4216 rootChineseCalendar->set(datePtr->year, datePtr->month-1, datePtr->day);
4217 rootChineseCalendar->set(UCAL_IS_LEAP_MONTH, datePtr->isLeapMonth);
4218 UnicodeString result;
4219 FieldPosition fpos(FieldPosition::DONT_CARE);
4220 dmft->format(*rootChineseCalendar, result, fpos);
4221 if ( result.compare(itemPtr->dateString[idate]) != 0 ) {
4222 errln( UnicodeString("FAIL: Chinese calendar format for locale ") + UnicodeString(itemPtr->locale) + ", style " + itemPtr->style +
4223 ", expected \"" + itemPtr->dateString[idate] + "\", got \"" + result + "\"");
4224 } else {
4225 // formatted OK, try parse
4226 ParsePosition ppos(0);
4227 // ensure we are really parsing the fields we should be
4228 rootChineseCalendar->set(UCAL_YEAR, 1);
4229 rootChineseCalendar->set(UCAL_MONTH, 0);
4230 rootChineseCalendar->set(UCAL_IS_LEAP_MONTH, 0);
4231 rootChineseCalendar->set(UCAL_DATE, 1);
4232 //
4233 dmft->parse(result, *rootChineseCalendar, ppos);
4234 int32_t year = rootChineseCalendar->get(UCAL_YEAR, status);
4235 int32_t month = rootChineseCalendar->get(UCAL_MONTH, status) + 1;
4236 int32_t isLeapMonth = rootChineseCalendar->get(UCAL_IS_LEAP_MONTH, status);
4237 int32_t day = rootChineseCalendar->get(UCAL_DATE, status);
4238 if ( ppos.getIndex() < result.length() || year != datePtr->year || month != datePtr->month || isLeapMonth != datePtr->isLeapMonth || day != datePtr->day ) {
4239 errln( UnicodeString("FAIL: Chinese calendar parse for locale ") + UnicodeString(itemPtr->locale) + ", style " + itemPtr->style +
4240 ", string \"" + result + "\", expected " + datePtr->year +"-"+datePtr->month+"("+datePtr->isLeapMonth+")-"+datePtr->day + ", got pos " +
4241 ppos.getIndex() + " " + year +"-"+month+"("+isLeapMonth+")-"+day);
4242 }
4243 }
4244 }
4245 } else {
4246 dataerrln("Error creating SimpleDateFormat for Chinese calendar- %s", u_errorName(status));
4247 }
4248 delete dmft;
4249 } else {
4250 dataerrln("FAIL: Unable to create DateFormat for Chinese calendar- %s", u_errorName(status));
4251 }
4252 }
4253 delete rootChineseCalendar;
4254 } else {
4255 errln(UnicodeString("FAIL: Unable to create Calendar for root@calendar=chinese"));
4256 }
4257 }
4258
4259 typedef struct {
4260 const char * locale;
4261 UnicodeString pattern;
4262 UDisplayContext capitalizationContext;
4263 UnicodeString expectedFormat;
4264 } TestContextItem;
4265
TestContext()4266 void DateFormatTest::TestContext()
4267 {
4268 const UDate july022008 = 1215000001979.0;
4269 const TestContextItem items[] = {
4270 //locale pattern capitalizationContext expected formatted date
4271 { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_NONE, UnicodeString("juillet 2008") },
4272 #if !UCONFIG_NO_BREAK_ITERATION
4273 { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UnicodeString("juillet 2008") },
4274 { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, UnicodeString("Juillet 2008") },
4275 { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, UnicodeString("juillet 2008") },
4276 { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_FOR_STANDALONE, UnicodeString("Juillet 2008") },
4277 #endif
4278 { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_NONE, CharsToUnicodeString("\\u010Dervenec 2008") },
4279 #if !UCONFIG_NO_BREAK_ITERATION
4280 { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, CharsToUnicodeString("\\u010Dervenec 2008") },
4281 { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, CharsToUnicodeString("\\u010Cervenec 2008") },
4282 { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, CharsToUnicodeString("\\u010Cervenec 2008") },
4283 { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_FOR_STANDALONE, CharsToUnicodeString("\\u010Dervenec 2008") },
4284 #endif
4285 // terminator
4286 { nullptr, UnicodeString(""), (UDisplayContext)0, UnicodeString("") }
4287 };
4288 UErrorCode status = U_ZERO_ERROR;
4289 Calendar* cal = Calendar::createInstance(status);
4290 if (U_FAILURE(status)) {
4291 dataerrln(UnicodeString("FAIL: Unable to create Calendar for default timezone and locale."));
4292 } else {
4293 cal->setTime(july022008, status);
4294 const TestContextItem * itemPtr;
4295 for (itemPtr = items; itemPtr->locale != nullptr; itemPtr++ ) {
4296 Locale locale = Locale::createFromName(itemPtr->locale);
4297 status = U_ZERO_ERROR;
4298 SimpleDateFormat * sdmft = new SimpleDateFormat(itemPtr->pattern, locale, status);
4299 if (U_FAILURE(status)) {
4300 dataerrln(UnicodeString("FAIL: Unable to create SimpleDateFormat for specified pattern with locale ") + UnicodeString(itemPtr->locale));
4301 } else {
4302 sdmft->setContext(itemPtr->capitalizationContext, status);
4303 UnicodeString result;
4304 FieldPosition pos(FieldPosition::DONT_CARE);
4305 sdmft->format(*cal, result, pos);
4306 if (result.compare(itemPtr->expectedFormat) != 0) {
4307 errln(UnicodeString("FAIL: format for locale ") + UnicodeString(itemPtr->locale) +
4308 ", status " + (int)status +
4309 ", capitalizationContext " + (int)itemPtr->capitalizationContext +
4310 ", expected " + itemPtr->expectedFormat + ", got " + result);
4311 }
4312 }
4313 if (sdmft) {
4314 delete sdmft;
4315 }
4316 }
4317 }
4318 if (cal) {
4319 delete cal;
4320 }
4321 }
4322
4323 // test item for a particular locale + calendar and date format
4324 typedef struct {
4325 int32_t era;
4326 int32_t year;
4327 int32_t month;
4328 int32_t day;
4329 int32_t hour;
4330 int32_t minute;
4331 UnicodeString formattedDate;
4332 } CalAndFmtTestItem;
4333
4334 // test item giving locale + calendar, date format, and CalAndFmtTestItems
4335 typedef struct {
4336 const char * locale; // with calendar
4337 DateFormat::EStyle style;
4338 UnicodeString pattern; // ignored unless style == DateFormat::kNone
4339 const CalAndFmtTestItem *caftItems;
4340 } TestNonGregoItem;
4341
TestNonGregoFmtParse()4342 void DateFormatTest::TestNonGregoFmtParse()
4343 {
4344 // test items for he@calendar=hebrew, long date format
4345 const CalAndFmtTestItem cafti_he_hebrew_long[] = {
4346 { 0, 4999, 12, 29, 12, 0, CharsToUnicodeString("\\u05DB\\u05F4\\u05D8 \\u05D1\\u05D0\\u05DC\\u05D5\\u05DC \\u05D3\\u05F3\\u05EA\\u05EA\\u05E7\\u05E6\\u05F4\\u05D8") },
4347 { 0, 5100, 0, 1, 12, 0, CharsToUnicodeString("\\u05D0\\u05F3 \\u05D1\\u05EA\\u05E9\\u05E8\\u05D9 \\u05E7\\u05F3") },
4348 { 0, 5774, 5, 1, 12, 0, CharsToUnicodeString("\\u05D0\\u05F3 \\u05D1\\u05D0\\u05D3\\u05E8 \\u05D0\\u05F3 \\u05EA\\u05E9\\u05E2\\u05F4\\u05D3") },
4349 { 0, 5999, 12, 29, 12, 0, CharsToUnicodeString("\\u05DB\\u05F4\\u05D8 \\u05D1\\u05D0\\u05DC\\u05D5\\u05DC \\u05EA\\u05EA\\u05E7\\u05E6\\u05F4\\u05D8") },
4350 { 0, 6100, 0, 1, 12, 0, CharsToUnicodeString("\\u05D0\\u05F3 \\u05D1\\u05EA\\u05E9\\u05E8\\u05D9 \\u05D5\\u05F3\\u05E7\\u05F3") },
4351 { 0, 0, 0, 0, 0, 0, UnicodeString("") } // terminator
4352 };
4353 const CalAndFmtTestItem cafti_zh_chinese_custU[] = {
4354 { 78, 31, 0, 1, 12, 0, CharsToUnicodeString("2014\\u7532\\u5348\\u5E74\\u6B63\\u67081") },
4355 { 77, 31, 0, 1, 12, 0, CharsToUnicodeString("1954\\u7532\\u5348\\u5E74\\u6B63\\u67081") },
4356 { 0, 0, 0, 0, 0, 0, UnicodeString("") } // terminator
4357 };
4358 const CalAndFmtTestItem cafti_zh_chinese_custNoU[] = {
4359 { 78, 31, 0, 1, 12, 0, CharsToUnicodeString("2014\\u5E74\\u6B63\\u67081") },
4360 { 77, 31, 0, 1, 12, 0, CharsToUnicodeString("1954\\u5E74\\u6B63\\u67081") },
4361 { 0, 0, 0, 0, 0, 0, UnicodeString("") } // terminator
4362 };
4363 const CalAndFmtTestItem cafti_ja_japanese_custGy[] = {
4364 {235, 26, 2, 5, 12, 0, CharsToUnicodeString("2014(\\u5E73\\u621026)\\u5E743\\u67085\\u65E5") },
4365 {234, 60, 2, 5, 12, 0, CharsToUnicodeString("1985(\\u662D\\u548C60)\\u5E743\\u67085\\u65E5") },
4366 { 0, 0, 0, 0, 0, 0, UnicodeString("") } // terminator
4367 };
4368 const CalAndFmtTestItem cafti_ja_japanese_custNoGy[] = {
4369 {235, 26, 2, 5, 12, 0, CharsToUnicodeString("2014\\u5E743\\u67085\\u65E5") },
4370 {234, 60, 2, 5, 12, 0, CharsToUnicodeString("1985\\u5E743\\u67085\\u65E5") },
4371 { 0, 0, 0, 0, 0, 0, UnicodeString("") } // terminator
4372 };
4373 const CalAndFmtTestItem cafti_en_islamic_cust[] = {
4374 { 0, 1384, 0, 1, 12, 0, UnicodeString("1 Muh. 1384 AH, 1964") },
4375 { 0, 1436, 0, 1, 12, 0, UnicodeString("1 Muh. 1436 AH, 2014") },
4376 { 0, 1487, 0, 1, 12, 0, UnicodeString("1 Muh. 1487 AH, 2064") },
4377 { 0, 0, 0, 0, 0, 0, UnicodeString("") } // terminator
4378 };
4379 // overal test items
4380 const TestNonGregoItem items[] = {
4381 { "he@calendar=hebrew", DateFormat::kLong, UnicodeString(""), cafti_he_hebrew_long },
4382 { "zh@calendar=chinese", DateFormat::kNone, CharsToUnicodeString("rU\\u5E74MMMd"), cafti_zh_chinese_custU },
4383 { "zh@calendar=chinese", DateFormat::kNone, CharsToUnicodeString("r\\u5E74MMMd"), cafti_zh_chinese_custNoU },
4384 { "ja@calendar=japanese", DateFormat::kNone, CharsToUnicodeString("r(Gy)\\u5E74M\\u6708d\\u65E5"), cafti_ja_japanese_custGy },
4385 { "ja@calendar=japanese", DateFormat::kNone, CharsToUnicodeString("r\\u5E74M\\u6708d\\u65E5"), cafti_ja_japanese_custNoGy },
4386 { "en@calendar=islamic", DateFormat::kNone, UnicodeString("d MMM y G, r"), cafti_en_islamic_cust },
4387 { nullptr, DateFormat::kNone, UnicodeString(""), nullptr } // terminator
4388 };
4389 const TestNonGregoItem * itemPtr;
4390 for (itemPtr = items; itemPtr->locale != nullptr; itemPtr++) {
4391 Locale locale = Locale::createFromName(itemPtr->locale);
4392 LocalPointer<DateFormat> dfmt;
4393 UErrorCode status = U_ZERO_ERROR;
4394 if (itemPtr->style != DateFormat::kNone) {
4395 dfmt.adoptInstead(DateFormat::createDateInstance(itemPtr->style, locale));
4396 } else {
4397 dfmt.adoptInstead(new SimpleDateFormat(itemPtr->pattern, locale, status));
4398 }
4399 if (U_FAILURE(status)) {
4400 dataerrln("new SimpleDateFormat fails for locale %s", itemPtr->locale);
4401 } else if (!dfmt.isValid()) {
4402 dataerrln("DateFormat::createDateInstance fails for locale %s", itemPtr->locale);
4403 } else {
4404 LocalPointer<Calendar>cal((dfmt->getCalendar())->clone());
4405 if (!cal.isValid()) {
4406 dataerrln("(DateFormat::getCalendar)->clone() fails for locale %s", itemPtr->locale);
4407 } else {
4408 const CalAndFmtTestItem * caftItemPtr;
4409 for (caftItemPtr = itemPtr->caftItems; caftItemPtr->year != 0; caftItemPtr++) {
4410 cal->clear();
4411 cal->set(UCAL_ERA, caftItemPtr->era);
4412 cal->set(UCAL_YEAR, caftItemPtr->year);
4413 cal->set(UCAL_MONTH, caftItemPtr->month);
4414 cal->set(UCAL_DATE, caftItemPtr->day);
4415 cal->set(UCAL_HOUR_OF_DAY, caftItemPtr->hour);
4416 cal->set(UCAL_MINUTE, caftItemPtr->minute);
4417 UnicodeString result;
4418 FieldPosition fpos(FieldPosition::DONT_CARE);
4419 dfmt->format(*cal, result, fpos);
4420 if ( result.compare(caftItemPtr->formattedDate) != 0 ) {
4421 errln( UnicodeString("FAIL: date format for locale ") + UnicodeString(itemPtr->locale) + ", style " + itemPtr->style +
4422 ", expected \"" + caftItemPtr->formattedDate + "\", got \"" + result + "\"");
4423 } else {
4424 // formatted OK, try parse
4425 ParsePosition ppos(0);
4426 dfmt->parse(result, *cal, ppos);
4427 status = U_ZERO_ERROR;
4428 int32_t era = cal->get(UCAL_ERA, status);
4429 int32_t year = cal->get(UCAL_YEAR, status);
4430 int32_t month = cal->get(UCAL_MONTH, status);
4431 int32_t day = cal->get(UCAL_DATE, status);
4432 if ( U_FAILURE(status) || ppos.getIndex() < result.length() || era != caftItemPtr->era ||
4433 year != caftItemPtr->year || month != caftItemPtr->month || day != caftItemPtr->day ) {
4434 errln( UnicodeString("FAIL: date parse for locale ") + UnicodeString(itemPtr->locale) +
4435 ", style " + itemPtr->style + ", string \"" + result + "\", expected " +
4436 caftItemPtr->era +":"+caftItemPtr->year +"-"+caftItemPtr->month+"-"+caftItemPtr->day + ", got pos " +
4437 ppos.getIndex() + " " + year +"-"+month+"-"+day + " status " + UnicodeString(u_errorName(status)) );
4438 }
4439 }
4440 }
4441 }
4442 }
4443 }
4444 }
4445
4446 typedef struct {
4447 const char* localeID;
4448 DateFormat::EStyle style;
4449 UnicodeString expectPattern;
4450 UnicodeString expectFormat;
4451 } TestFmtWithNumSysItem;
4452 enum { kBBufMax = 128 };
TestFormatsWithNumberSystems()4453 void DateFormatTest::TestFormatsWithNumberSystems()
4454 {
4455 LocalPointer<TimeZone> zone(TimeZone::createTimeZone(UnicodeString("UTC")));
4456 const UDate date = 1451556000000.0; // for UTC: grego 31-Dec-2015 10 AM, hebrew 19 tevet 5776, chinese yi-wei 11mo 21day
4457 const TestFmtWithNumSysItem items[] = {
4458 { "haw@calendar=gregorian", DateFormat::kShort, UnicodeString("d/M/yy"), UnicodeString("31/xii/15") },
4459 { "he@calendar=hebrew", DateFormat::kLong, CharsToUnicodeString("d \\u05D1MMMM y"), CharsToUnicodeString("\\u05D9\\u05F4\\u05D8 \\u05D1\\u05D8\\u05D1\\u05EA \\u05EA\\u05E9\\u05E2\\u05F4\\u05D5") },
4460 { "zh@calendar=chinese", DateFormat::kLong, CharsToUnicodeString("rU\\u5E74MMMd"), CharsToUnicodeString("2015\\u4E59\\u672A\\u5E74\\u5341\\u4E00\\u6708\\u5EFF\\u4E00") },
4461 { "zh_Hant@calendar=chinese", DateFormat::kLong, CharsToUnicodeString("rU\\u5E74MMMd"), CharsToUnicodeString("2015\\u4E59\\u672A\\u5E74\\u51AC\\u6708\\u5EFF\\u4E00") },
4462 { "ja@calendar=chinese", DateFormat::kLong, CharsToUnicodeString("U\\u5E74MMMd\\u65E5"), CharsToUnicodeString("\\u4E59\\u672A\\u5E74\\u5341\\u4E00\\u6708\\u4E8C\\u4E00\\u65E5") },
4463 { nullptr, DateFormat::kNone, UnicodeString(""), UnicodeString("") },
4464 };
4465 const TestFmtWithNumSysItem * itemPtr;
4466 for (itemPtr = items; itemPtr->localeID != nullptr; itemPtr++) {
4467 char bExpected[kBBufMax];
4468 char bResult[kBBufMax];
4469 UErrorCode status = U_ZERO_ERROR;
4470 Locale locale = Locale::createFromName(itemPtr->localeID);
4471 LocalPointer<Calendar> cal(Calendar::createInstance(zone.orphan(), locale, status));
4472 if (U_FAILURE(status)) {
4473 dataerrln("Calendar::createInstance fails for locale %s, status %s", itemPtr->localeID, u_errorName(status));
4474 continue;
4475 }
4476 cal->setTime(date, status);
4477 if (U_FAILURE(status)) {
4478 dataerrln("Calendar::setTime fails for locale %s, date %.1f, status %s", itemPtr->localeID, date, u_errorName(status));
4479 continue;
4480 }
4481 LocalPointer<SimpleDateFormat> sdfmt(dynamic_cast<SimpleDateFormat *>(DateFormat::createDateInstance(itemPtr->style, locale)));
4482 if (sdfmt.isNull()) {
4483 dataerrln("DateFormat::createDateInstance fails for locale %s", itemPtr->localeID);
4484 continue;
4485 }
4486 UnicodeString getFormat;
4487 sdfmt->format(*(cal.getAlias()), getFormat, nullptr, status);
4488 if (U_FAILURE(status)) {
4489 errln("DateFormat::format fails for locale %s, status %s", itemPtr->localeID, u_errorName(status));
4490 continue;
4491 }
4492 if (getFormat.compare(itemPtr->expectFormat) != 0) {
4493 itemPtr->expectFormat.extract(0, itemPtr->expectFormat.length(), bExpected, kBBufMax);
4494 getFormat.extract(0, getFormat.length(), bResult, kBBufMax);
4495 errln("DateFormat::format for locale %s, expected \"%s\", got \"%s\"", itemPtr->localeID, bExpected, bResult);
4496 }
4497 UnicodeString getPattern;
4498 sdfmt->toPattern(getPattern);
4499 if (getPattern.compare(itemPtr->expectPattern) != 0) {
4500 itemPtr->expectPattern.extract(0, itemPtr->expectPattern.length(), bExpected, kBBufMax);
4501 getPattern.extract(0, getPattern.length(), bResult, kBBufMax);
4502 errln("DateFormat::toPattern() for locale %s, expected \"%s\", got \"%s\"", itemPtr->localeID, bExpected, bResult);
4503 }
4504 }
4505 }
4506
4507 static const UDate TEST_DATE = 1326585600000.; // 2012-jan-15
4508
TestDotAndAtLeniency()4509 void DateFormatTest::TestDotAndAtLeniency() {
4510 // Test for date/time parsing regression with CLDR 22.1/ICU 50 pattern strings.
4511 // For details see https://unicode-org.atlassian.net/browse/ICU-9789
4512 static const char *locales[] = { "en", "fr" };
4513 for (int32_t i = 0; i < UPRV_LENGTHOF(locales); ++i) {
4514 Locale locale(locales[i]);
4515
4516 for (DateFormat::EStyle dateStyle = DateFormat::FULL; dateStyle <= DateFormat::SHORT;
4517 dateStyle = static_cast<DateFormat::EStyle>(dateStyle + 1)) {
4518 LocalPointer<DateFormat> dateFormat(DateFormat::createDateInstance(dateStyle, locale));
4519
4520 for (DateFormat::EStyle timeStyle = DateFormat::FULL; timeStyle <= DateFormat::SHORT;
4521 timeStyle = static_cast<DateFormat::EStyle>(timeStyle + 1)) {
4522 LocalPointer<DateFormat> format(DateFormat::createDateTimeInstance(dateStyle, timeStyle, locale));
4523 LocalPointer<DateFormat> timeFormat(DateFormat::createTimeInstance(timeStyle, locale));
4524 UnicodeString formattedString;
4525 if (format.isNull()) {
4526 dataerrln("Unable to create DateFormat");
4527 continue;
4528 }
4529 format->format(TEST_DATE, formattedString);
4530
4531 if (!showParse(*format, formattedString)) {
4532 errln(UnicodeString(" with date-time: dateStyle=") + dateStyle + " timeStyle=" + timeStyle);
4533 }
4534
4535 UnicodeString ds, ts;
4536 formattedString = dateFormat->format(TEST_DATE, ds) + " " + timeFormat->format(TEST_DATE, ts);
4537 if (!showParse(*format, formattedString)) {
4538 errln(UnicodeString(" with date sp sp time: dateStyle=") + dateStyle + " timeStyle=" + timeStyle);
4539 }
4540 if (formattedString.indexOf("n ") >= 0) { // will add "." after the end of text ending in 'n', like Jan.
4541 UnicodeString plusDot(formattedString);
4542 plusDot.findAndReplace("n ", "n. ").append(".");
4543 if (!showParse(*format, plusDot)) {
4544 errln(UnicodeString(" with date plus-dot time: dateStyle=") + dateStyle + " timeStyle=" + timeStyle);
4545 }
4546 }
4547 if (formattedString.indexOf(". ") >= 0) { // will subtract "." at the end of strings.
4548 UnicodeString minusDot(formattedString);
4549 minusDot.findAndReplace(". ", " ");
4550 if (!showParse(*format, minusDot)) {
4551 errln(UnicodeString(" with date minus-dot time: dateStyle=") + dateStyle + " timeStyle=" + timeStyle);
4552 }
4553 }
4554 }
4555 }
4556 }
4557 }
4558
showParse(DateFormat & format,const UnicodeString & formattedString)4559 UBool DateFormatTest::showParse(DateFormat &format, const UnicodeString &formattedString) {
4560 ParsePosition parsePosition;
4561 UDate parsed = format.parse(formattedString, parsePosition);
4562 UBool ok = TEST_DATE == parsed && parsePosition.getIndex() == formattedString.length();
4563 UnicodeString pattern;
4564 dynamic_cast<SimpleDateFormat &>(format).toPattern(pattern);
4565 if (ok) {
4566 logln(pattern + " parsed: " + formattedString);
4567 } else {
4568 errln(pattern + " fails to parse: " + formattedString);
4569 }
4570 return ok;
4571 }
4572
4573
4574 typedef struct {
4575 const char * locale;
4576 UBool leniency;
4577 UnicodeString parseString;
4578 UnicodeString pattern;
4579 UnicodeString expectedResult; // empty string indicates expected error
4580 } TestDateFormatLeniencyItem;
4581
TestDateFormatLeniency()4582 void DateFormatTest::TestDateFormatLeniency() {
4583 // For details see https://unicode-org.atlassian.net/browse/ICU-10261
4584
4585 const UDate july022008 = 1215000001979.0;
4586 const TestDateFormatLeniencyItem items[] = {
4587 //locale leniency parse String pattern expected result
4588 { "en", true, UnicodeString("2008-07 02"), UnicodeString("yyyy-LLLL dd"), UnicodeString("2008-July 02") },
4589 { "en", false, UnicodeString("2008-07 02"), UnicodeString("yyyy-LLLL dd"), UnicodeString("") },
4590 { "en", true, UnicodeString("2008-Jan 02"), UnicodeString("yyyy-LLL. dd"), UnicodeString("2008-Jan. 02") },
4591 { "en", false, UnicodeString("2008-Jan 02"), UnicodeString("yyyy-LLL. dd"), UnicodeString("") },
4592 { "en", true, UnicodeString("2008-Jan--02"), UnicodeString("yyyy-MMM' -- 'dd"), UnicodeString("2008-Jan -- 02") },
4593 { "en", false, UnicodeString("2008-Jan--02"), UnicodeString("yyyy-MMM' -- 'dd"), UnicodeString("") },
4594 // terminator
4595 { nullptr, true, UnicodeString(""), UnicodeString(""), UnicodeString("") }
4596 };
4597 UErrorCode status = U_ZERO_ERROR;
4598 LocalPointer<Calendar> cal(Calendar::createInstance(status));
4599 if (U_FAILURE(status)) {
4600 dataerrln(UnicodeString("FAIL: Unable to create Calendar for default timezone and locale."));
4601 return;
4602 }
4603 cal->setTime(july022008, status);
4604 const TestDateFormatLeniencyItem * itemPtr;
4605 LocalPointer<SimpleDateFormat> sdmft;
4606 for (itemPtr = items; itemPtr->locale != nullptr; itemPtr++ ) {
4607
4608 Locale locale = Locale::createFromName(itemPtr->locale);
4609 status = U_ZERO_ERROR;
4610 ParsePosition pos(0);
4611 sdmft.adoptInsteadAndCheckErrorCode(new SimpleDateFormat(itemPtr->pattern, locale, status), status);
4612 if (U_FAILURE(status)) {
4613 dataerrln("Unable to create SimpleDateFormat - %s", u_errorName(status));
4614 continue;
4615 }
4616 sdmft->setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, itemPtr->leniency, status).
4617 setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, itemPtr->leniency, status).
4618 setBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, itemPtr->leniency, status);
4619 UDate d = sdmft->parse(itemPtr->parseString, pos);
4620
4621 if(itemPtr->expectedResult.length() == 0) {
4622 if(pos.getErrorIndex() != -1) {
4623 continue;
4624 } else {
4625 errln("error: unexpected parse success - " + itemPtr->parseString +
4626 " - pattern " + itemPtr->pattern +
4627 " - error index " + pos.getErrorIndex() +
4628 " - leniency " + itemPtr->leniency);
4629 continue;
4630 }
4631 }
4632 if(pos.getErrorIndex() != -1) {
4633 errln("error: parse error for string - " + itemPtr->parseString +
4634 " - pattern " + itemPtr->pattern +
4635 " - idx " + pos.getIndex() +
4636 " - error index "+pos.getErrorIndex() +
4637 " - leniency " + itemPtr->leniency);
4638 continue;
4639 }
4640
4641 UnicodeString formatResult("");
4642 sdmft->format(d, formatResult);
4643 if(formatResult.compare(itemPtr->expectedResult) != 0) {
4644 errln("error: unexpected format result. pattern["+itemPtr->pattern+"] expected[" + itemPtr->expectedResult + "] but result was[" + formatResult + "]");
4645 continue;
4646 } else {
4647 logln("formatted results match! - " + formatResult);
4648 }
4649
4650 }
4651 }
4652
4653
4654 typedef struct {
4655 UBool leniency;
4656 UnicodeString parseString;
4657 UnicodeString pattern;
4658 UnicodeString expectedResult; // empty string indicates expected error
4659 } TestMultiPatternMatchItem;
4660
TestParseMultiPatternMatch()4661 void DateFormatTest::TestParseMultiPatternMatch() {
4662 // For details see https://unicode-org.atlassian.net/browse/ICU-10336
4663 const TestMultiPatternMatchItem items[] = {
4664 // leniency parse String pattern expected result
4665 {true, UnicodeString("2013-Sep 13"), UnicodeString("yyyy-MMM dd"), UnicodeString("2013-Sep 13")},
4666 {true, UnicodeString("2013-September 14"), UnicodeString("yyyy-MMM dd"), UnicodeString("2013-Sep 14")},
4667 {false, UnicodeString("2013-September 15"), UnicodeString("yyyy-MMM dd"), UnicodeString("")},
4668 {false, UnicodeString("2013-September 16"), UnicodeString("yyyy-MMMM dd"), UnicodeString("2013-September 16")},
4669 {true, UnicodeString("2013-Sep 17"), UnicodeString("yyyy-LLL dd"), UnicodeString("2013-Sep 17")},
4670 {true, UnicodeString("2013-September 18"), UnicodeString("yyyy-LLL dd"), UnicodeString("2013-Sep 18")},
4671 {false, UnicodeString("2013-September 19"), UnicodeString("yyyy-LLL dd"), UnicodeString("")},
4672 {false, UnicodeString("2013-September 20"), UnicodeString("yyyy-LLLL dd"), UnicodeString("2013-September 20")},
4673 {true, UnicodeString("2013 Sat Sep 21"), UnicodeString("yyyy EEE MMM dd"), UnicodeString("2013 Sat Sep 21")},
4674 {true, UnicodeString("2013 Sunday Sep 22"), UnicodeString("yyyy EEE MMM dd"), UnicodeString("2013 Sun Sep 22")},
4675 {false, UnicodeString("2013 Monday Sep 23"), UnicodeString("yyyy EEE MMM dd"), UnicodeString("")},
4676 {false, UnicodeString("2013 Tuesday Sep 24"), UnicodeString("yyyy EEEE MMM dd"), UnicodeString("2013 Tuesday Sep 24")},
4677 {true, UnicodeString("2013 Wed Sep 25"), UnicodeString("yyyy eee MMM dd"), UnicodeString("2013 Wed Sep 25")},
4678 {true, UnicodeString("2013 Thu Sep 26"), UnicodeString("yyyy eee MMM dd"), UnicodeString("2013 Thu Sep 26")},
4679 {false, UnicodeString("2013 Friday Sep 27"), UnicodeString("yyyy eee MMM dd"), UnicodeString("")},
4680 {false, UnicodeString("2013 Saturday Sep 28"), UnicodeString("yyyy eeee MMM dd"), UnicodeString("2013 Saturday Sep 28")},
4681 {true, UnicodeString("2013 Sun Sep 29"), UnicodeString("yyyy ccc MMM dd"), UnicodeString("2013 Sun Sep 29")},
4682 {true, UnicodeString("2013 Monday Sep 30"), UnicodeString("yyyy ccc MMM dd"), UnicodeString("2013 Mon Sep 30")},
4683 {false, UnicodeString("2013 Sunday Oct 13"), UnicodeString("yyyy ccc MMM dd"), UnicodeString("")},
4684 {false, UnicodeString("2013 Monday Oct 14"), UnicodeString("yyyy cccc MMM dd"), UnicodeString("2013 Monday Oct 14")},
4685 {true, UnicodeString("2013 Oct 15 Q4"), UnicodeString("yyyy MMM dd QQQ"), UnicodeString("2013 Oct 15 Q4")},
4686 {true, UnicodeString("2013 Oct 16 4th quarter"), UnicodeString("yyyy MMM dd QQQ"), UnicodeString("2013 Oct 16 Q4")},
4687 {false, UnicodeString("2013 Oct 17 4th quarter"), UnicodeString("yyyy MMM dd QQQ"), UnicodeString("")},
4688 {false, UnicodeString("2013 Oct 18 Q4"), UnicodeString("yyyy MMM dd QQQ"), UnicodeString("2013 Oct 18 Q4")},
4689 {true, UnicodeString("2013 Oct 19 Q4"), UnicodeString("yyyy MMM dd qqqq"), UnicodeString("2013 Oct 19 4th quarter")},
4690 {true, UnicodeString("2013 Oct 20 4th quarter"), UnicodeString("yyyy MMM dd qqqq"), UnicodeString("2013 Oct 20 4th quarter")},
4691 {false, UnicodeString("2013 Oct 21 Q4"), UnicodeString("yyyy MMM dd qqqq"), UnicodeString("")},
4692 {false, UnicodeString("2013 Oct 22 4th quarter"), UnicodeString("yyyy MMM dd qqqq"), UnicodeString("2013 Oct 22 4th quarter")},
4693 {false, UnicodeString("--end--"), UnicodeString(""), UnicodeString("")},
4694 };
4695
4696 UErrorCode status = U_ZERO_ERROR;
4697 LocalPointer<Calendar> cal(Calendar::createInstance(status));
4698 if (U_FAILURE(status)) {
4699 dataerrln(UnicodeString("FAIL: Unable to create Calendar for default timezone and locale."));
4700 return;
4701 }
4702 const TestMultiPatternMatchItem * itemPtr;
4703 DateFormat* sdmft = DateFormat::createDateInstance();
4704 if (sdmft == nullptr) {
4705 dataerrln(UnicodeString("FAIL: Unable to create DateFormat"));
4706 return;
4707 }
4708 for (itemPtr = items; itemPtr->parseString != "--end--"; itemPtr++ ) {
4709 status = U_ZERO_ERROR;
4710 ParsePosition pos(0);
4711 (dynamic_cast<SimpleDateFormat*>(sdmft))->applyPattern(itemPtr->pattern);
4712 if (U_FAILURE(status)) {
4713 dataerrln("Unable to create SimpleDateFormat - %s", u_errorName(status));
4714 continue;
4715 }
4716 sdmft->setBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, itemPtr->leniency, status);
4717 UDate d = sdmft->parse(itemPtr->parseString, pos);
4718
4719 if(itemPtr->expectedResult.length() == 0) {
4720 if(pos.getErrorIndex() != -1) {
4721 continue;
4722 } else {
4723 errln("error: unexpected parse success - " + itemPtr->parseString +
4724 " - error index " + pos.getErrorIndex() +
4725 " - leniency " + itemPtr->leniency);
4726 continue;
4727 }
4728 }
4729 if(pos.getErrorIndex() != -1) {
4730 errln("error: parse error for string - " +itemPtr->parseString + " -- idx["+pos.getIndex()+"] errIdx["+pos.getErrorIndex()+"]");
4731 continue;
4732 }
4733
4734 UnicodeString formatResult("");
4735 sdmft->format(d, formatResult);
4736 if(formatResult.compare(itemPtr->expectedResult) != 0) {
4737 errln("error: unexpected format result. expected[" + itemPtr->expectedResult + "] but result was[" + formatResult + "]");
4738 } else {
4739 logln("formatted results match! - " + formatResult);
4740 }
4741 }
4742 delete sdmft;
4743 }
4744
TestParseLeniencyAPIs()4745 void DateFormatTest::TestParseLeniencyAPIs() {
4746 UErrorCode status = U_ZERO_ERROR;
4747 LocalPointer<DateFormat> dateFormat(DateFormat::createDateInstance());
4748 DateFormat *fmt = dateFormat.getAlias();
4749 if (fmt == nullptr) {
4750 dataerrln("Failed calling dateFormat.getAlias()");
4751 return;
4752 }
4753
4754 assertTrue("isLenient default", fmt->isLenient());
4755 assertTrue("isCalendarLenient default", fmt->isCalendarLenient());
4756 assertTrue("ALLOW_WHITESPACE default", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status));
4757 assertTrue("ALLOW_NUMERIC default", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status));
4758 assertTrue("PARTIAL_MATCH default", fmt->getBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, status));
4759 assertTrue("MULTIPLE_PATTERNS default", fmt->getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status));
4760
4761 // Set calendar to strict
4762 fmt->setCalendarLenient(false);
4763
4764 assertFalse("isLenient after setCalendarLenient(false)", fmt->isLenient());
4765 assertFalse("isCalendarLenient after setCalendarLenient(false)", fmt->isCalendarLenient());
4766 assertTrue("ALLOW_WHITESPACE after setCalendarLenient(false)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status));
4767 assertTrue("ALLOW_NUMERIC after setCalendarLenient(false)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status));
4768
4769 // Set to strict
4770 fmt->setLenient(false);
4771
4772 assertFalse("isLenient after setLenient(false)", fmt->isLenient());
4773 assertFalse("isCalendarLenient after setLenient(false)", fmt->isCalendarLenient());
4774 assertFalse("ALLOW_WHITESPACE after setLenient(false)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status));
4775 assertFalse("ALLOW_NUMERIC after setLenient(false)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status));
4776 // These two boolean attributes are NOT affected according to the API specification
4777 assertTrue("PARTIAL_MATCH after setLenient(false)", fmt->getBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, status));
4778 assertTrue("MULTIPLE_PATTERNS after setLenient(false)", fmt->getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status));
4779
4780 // Allow white space leniency
4781 fmt->setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status);
4782
4783 assertFalse("isLenient after ALLOW_WHITESPACE/true", fmt->isLenient());
4784 assertFalse("isCalendarLenient after ALLOW_WHITESPACE/true", fmt->isCalendarLenient());
4785 assertTrue("ALLOW_WHITESPACE after ALLOW_WHITESPACE/true", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status));
4786 assertFalse("ALLOW_NUMERIC after ALLOW_WHITESPACE/true", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status));
4787
4788 // Set to lenient
4789 fmt->setLenient(true);
4790
4791 assertTrue("isLenient after setLenient(true)", fmt->isLenient());
4792 assertTrue("isCalendarLenient after setLenient(true)", fmt->isCalendarLenient());
4793 assertTrue("ALLOW_WHITESPACE after setLenient(true)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status));
4794 assertTrue("ALLOW_NUMERIC after setLenient(true)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status));
4795 }
4796
TestNumberFormatOverride()4797 void DateFormatTest::TestNumberFormatOverride() {
4798 UErrorCode status = U_ZERO_ERROR;
4799 UnicodeString fields = (UnicodeString) "M";
4800
4801 LocalPointer<SimpleDateFormat> fmt;
4802 fmt.adoptInsteadAndCheckErrorCode(new SimpleDateFormat((UnicodeString)"MM d", status), status);
4803 if (!assertSuccess("SimpleDateFormat with pattern MM d", status)) {
4804 return;
4805 }
4806
4807
4808 for(int i=0; i<3; i++){
4809 NumberFormat* check_nf = NumberFormat::createInstance(Locale("en_US"), status);
4810 assertSuccess("NumberFormat en_US", status);
4811 fmt->adoptNumberFormat(fields, check_nf, status);
4812 assertSuccess("adoptNumberFormat check_nf", status);
4813
4814 const NumberFormat* get_nf = fmt->getNumberFormatForField((char16_t)0x004D /*'M'*/);
4815 if (get_nf != check_nf) errln("FAIL: getter and setter do not work");
4816 }
4817 NumberFormat* check_nf = NumberFormat::createInstance(Locale("en_US"), status);
4818 assertSuccess("NumberFormat en_US", status);
4819 fmt->adoptNumberFormat(check_nf); // make sure using the same NF will not crash
4820
4821 const char * DATA [][2] = {
4822 { "", "\\u521D\\u516D \\u5341\\u4E94"},
4823 { "M", "\\u521D\\u516D 15"},
4824 { "Mo", "\\u521D\\u516D 15"},
4825 { "Md", "\\u521D\\u516D \\u5341\\u4E94"},
4826 { "MdMMd", "\\u521D\\u516D \\u5341\\u4E94"},
4827 { "mixed", "\\u521D\\u516D \\u5341\\u4E94"}
4828 };
4829
4830 UDate test_date = date(97, 6 - 1, 15);
4831
4832 for(int i=0; i < UPRV_LENGTHOF(DATA); i++){
4833 fields = DATA[i][0];
4834
4835 LocalPointer<SimpleDateFormat> fmt;
4836 fmt.adoptInsteadAndCheckErrorCode(new SimpleDateFormat((UnicodeString)"MM d", status), status);
4837 assertSuccess("SimpleDateFormat with pattern MM d", status);
4838 NumberFormat* overrideNF = NumberFormat::createInstance(Locale::createFromName("zh@numbers=hanidays"),status);
4839 assertSuccess("NumberFormat zh@numbers=hanidays", status);
4840 if (U_FAILURE(status)) {
4841 status = U_ZERO_ERROR;
4842 continue;
4843 }
4844
4845 if (fields == (UnicodeString) "") { // use the one w/o fields
4846 fmt->adoptNumberFormat(overrideNF);
4847 } else if (fields == (UnicodeString) "mixed") { // set 1 field at first but then full override, both(M & d) should be override
4848 NumberFormat* singleOverrideNF = NumberFormat::createInstance(Locale::createFromName("en@numbers=hebr"),status);
4849 assertSuccess("NumberFormat en@numbers=hebr", status);
4850
4851 fields = (UnicodeString) "M";
4852 fmt->adoptNumberFormat(fields, singleOverrideNF, status);
4853 assertSuccess("adoptNumberFormat singleOverrideNF", status);
4854
4855 fmt->adoptNumberFormat(overrideNF);
4856 } else if (fields == (UnicodeString) "Mo"){ // o is invalid field
4857 fmt->adoptNumberFormat(fields, overrideNF, status);
4858 if(status == U_INVALID_FORMAT_ERROR) {
4859 status = U_ZERO_ERROR;
4860 continue;
4861 }
4862 } else {
4863 fmt->adoptNumberFormat(fields, overrideNF, status);
4864 assertSuccess("adoptNumberFormat overrideNF", status);
4865 }
4866
4867 UnicodeString result;
4868 FieldPosition pos(FieldPosition::DONT_CARE);
4869 fmt->format(test_date,result, pos);
4870
4871 UnicodeString expected = ((UnicodeString)DATA[i][1]).unescape();
4872
4873 if (result != expected)
4874 errln("FAIL: Expected " + expected + " get: " + result);
4875
4876 // Ensure that adopted formats are handled correctly after copy constructing
4877 SimpleDateFormat fmtCopy = *fmt;
4878 result.remove();
4879 fmtCopy.format(test_date,result, pos);
4880 if (result != expected)
4881 errln("FAIL: Expected " + expected + " after copy constructing get: " + result);
4882 }
4883 }
4884
TestCreateInstanceForSkeleton()4885 void DateFormatTest::TestCreateInstanceForSkeleton() {
4886 UErrorCode status = U_ZERO_ERROR;
4887 LocalPointer<DateFormat> fmt(DateFormat::createInstanceForSkeleton(
4888 "yMMMMd", "en", status));
4889 if (!assertSuccess("Create with pattern yMMMMd", status)) {
4890 return;
4891 }
4892 UnicodeString result;
4893 FieldPosition pos(FieldPosition::DONT_CARE);
4894 fmt->format(date(98, 5-1, 25), result, pos);
4895 assertEquals("format yMMMMd", "May 25, 1998", result);
4896 fmt.adoptInstead(DateFormat::createInstanceForSkeleton(
4897 "yMd", "en", status));
4898 if (!assertSuccess("Create with pattern yMd", status)) {
4899 return;
4900 }
4901 result.remove();
4902 fmt->format(date(98, 5-1, 25), result, pos);
4903 assertEquals("format yMd", "5/25/1998", result);
4904 }
4905
TestCreateInstanceForSkeletonDefault()4906 void DateFormatTest::TestCreateInstanceForSkeletonDefault() {
4907 UErrorCode status = U_ZERO_ERROR;
4908 Locale savedLocale;
4909 Locale::setDefault(Locale::getUS(), status);
4910 LocalPointer<DateFormat> fmt(DateFormat::createInstanceForSkeleton(
4911 "yMMMd", status));
4912 Locale::setDefault(savedLocale, status);
4913 if (!assertSuccess("Create with pattern yMMMd", status)) {
4914 return;
4915 }
4916 UnicodeString result;
4917 FieldPosition pos(FieldPosition::DONT_CARE);
4918 fmt->format(date(98, 5-1, 25), result, pos);
4919 assertEquals("format yMMMd", "May 25, 1998", result);
4920 }
4921
TestCreateInstanceForSkeletonWithCalendar()4922 void DateFormatTest::TestCreateInstanceForSkeletonWithCalendar() {
4923 UErrorCode status = U_ZERO_ERROR;
4924 LocalPointer<DateFormat> fmt(
4925 DateFormat::createInstanceForSkeleton(
4926 Calendar::createInstance(
4927 TimeZone::createTimeZone("GMT-3:00"),
4928 status),
4929 "yMdHm", "en", status));
4930 if (!assertSuccess("Create with pattern yMMMMd", status)) {
4931 return;
4932 }
4933 UnicodeString result;
4934 FieldPosition pos(FieldPosition::DONT_CARE);
4935
4936 LocalPointer<Calendar> cal(Calendar::createInstance(
4937 TimeZone::createTimeZone("GMT-7:00"),
4938 status));
4939 if (!assertSuccess("Creating GMT-7 time zone failed", status)) {
4940 return;
4941 }
4942 cal->clear();
4943 cal->set(1998, 5-1, 25, 0, 0, 0);
4944
4945 // date format time zone should be 4 hours ahead.
4946 fmt->format(cal->getTime(status), result, pos);
4947 assertEquals("format yMdHm", "5/25/1998, 04:00", result);
4948 assertSuccess("", status);
4949 }
4950
TestDFSCreateForLocaleNonGregorianLocale()4951 void DateFormatTest::TestDFSCreateForLocaleNonGregorianLocale() {
4952 UErrorCode status = U_ZERO_ERROR;
4953 Locale fa("fa");
4954 LocalPointer<DateFormatSymbols> sym(
4955 DateFormatSymbols::createForLocale(fa, status));
4956 if (!assertSuccess("", status)) {
4957 return;
4958 }
4959
4960 // Farsi should default to the persian calendar, not gregorian
4961 int32_t count;
4962 const UnicodeString *months = sym->getShortMonths(count);
4963
4964 // First persian month.
4965 UnicodeString expected("\\u0641\\u0631\\u0648\\u0631\\u062f\\u06cc\\u0646");
4966 assertEquals("", expected.unescape(), months[0]);
4967 }
4968
TestDFSCreateForLocaleWithCalendarInLocale()4969 void DateFormatTest::TestDFSCreateForLocaleWithCalendarInLocale() {
4970 UErrorCode status = U_ZERO_ERROR;
4971 Locale en_heb("en@calendar=hebrew");
4972 LocalPointer<DateFormatSymbols> sym(
4973 DateFormatSymbols::createForLocale(en_heb, status));
4974 if (!assertSuccess("", status)) {
4975 return;
4976 }
4977
4978 // We should get the months of the hebrew calendar, not the gregorian
4979 // calendar.
4980 int32_t count;
4981 const UnicodeString *months = sym->getShortMonths(count);
4982
4983 // First hebrew month.
4984 UnicodeString expected("Tishri");
4985 assertEquals("", expected, months[0]);
4986 }
4987
TestChangeCalendar()4988 void DateFormatTest::TestChangeCalendar() {
4989 UErrorCode status = U_ZERO_ERROR;
4990 Locale en("en");
4991 Locale en_heb("en@calendar=hebrew");
4992 LocalPointer<DateFormat> fmt(
4993 DateFormat::createInstanceForSkeleton("yMMMd", en, status));
4994 if (!assertSuccess("", status)) {
4995 return;
4996 }
4997 fmt->adoptCalendar(Calendar::createInstance(en_heb, status));
4998 if (!assertSuccess("", status)) {
4999 return;
5000 }
5001 UnicodeString result;
5002 FieldPosition pos(FieldPosition::DONT_CARE);
5003 fmt->format(date(98, 5-1, 25), result, pos);
5004 assertEquals("format yMMMd", "Iyar 29, 5758", result);
5005 }
5006
TestPatternFromSkeleton()5007 void DateFormatTest::TestPatternFromSkeleton() {
5008 static const struct {
5009 const Locale& locale;
5010 const char* const skeleton;
5011 const char16_t* const pattern;
5012 } TESTDATA[] = {
5013 // Ticket #11985
5014 {Locale::getEnglish(), "jjmm", u"h:mm\u202Fa"},
5015 {Locale::getEnglish(), "JJmm", u"hh:mm"},
5016 {Locale::getGerman(), "jjmm", u"HH:mm"},
5017 {Locale::getGerman(), "JJmm", u"HH:mm"},
5018 // Ticket #20739
5019 // minutes+milliseconds, seconds missing, should be repaired
5020 {Locale::getEnglish(), "SSSSm", u"mm:ss.SSSS"},
5021 {Locale::getEnglish(), "mSSSS", u"mm:ss.SSSS"},
5022 {Locale::getEnglish(), "SSSm", u"mm:ss.SSS"},
5023 {Locale::getEnglish(), "mSSS", u"mm:ss.SSS"},
5024 {Locale::getEnglish(), "SSm", u"mm:ss.SS"},
5025 {Locale::getEnglish(), "mSS", u"mm:ss.SS"},
5026 {Locale::getEnglish(), "Sm", u"mm:ss.S"},
5027 {Locale::getEnglish(), "mS", u"mm:ss.S"},
5028 // only milliseconds, untouched, no repairs
5029 {Locale::getEnglish(), "S", u"S"},
5030 {Locale::getEnglish(), "SS", u"SS"},
5031 {Locale::getEnglish(), "SSS", u"SSS"},
5032 {Locale::getEnglish(), "SSSS", u"SSSS"},
5033 // hour:minute+seconds+milliseconds, correct, no repairs, proper pattern
5034 {Locale::getEnglish(), "jmsSSS", u"h:mm:ss.SSS\u202Fa"},
5035 {Locale::getEnglish(), "jmSSS", u"h:mm:ss.SSS\u202Fa"},
5036 // Ticket #20738
5037 // seconds+milliseconds, correct, no repairs, proper pattern
5038 {Locale::getEnglish(), "sS", u"s.S"},
5039 {Locale::getEnglish(), "sSS", u"s.SS"},
5040 {Locale::getEnglish(), "sSSS", u"s.SSS"},
5041 {Locale::getEnglish(), "sSSSS", u"s.SSSS"},
5042 {Locale::getEnglish(), "sS", u"s.S"},
5043 // minutes+seconds+milliseconds, correct, no repairs, proper pattern
5044 {Locale::getEnglish(), "msS", u"mm:ss.S"},
5045 {Locale::getEnglish(), "msSS", u"mm:ss.SS"},
5046 {Locale::getEnglish(), "msSSS", u"mm:ss.SSS"},
5047 {Locale::getEnglish(), "msSSSS", u"mm:ss.SSSS"}
5048 };
5049
5050 for (size_t i = 0; i < UPRV_LENGTHOF(TESTDATA); i++) {
5051 UErrorCode status = U_ZERO_ERROR;
5052 LocalPointer<DateFormat> fmt(
5053 DateFormat::createInstanceForSkeleton(
5054 TESTDATA[i].skeleton, TESTDATA[i].locale, status));
5055 if (!assertSuccess("createInstanceForSkeleton", status)) {
5056 return;
5057 }
5058 UnicodeString pattern;
5059 dynamic_cast<const SimpleDateFormat*>(fmt.getAlias())->toPattern(pattern);
5060 assertEquals("Format pattern", TESTDATA[i].pattern, pattern);
5061 }
5062 }
5063
TestAmPmMidnightNoon()5064 void DateFormatTest::TestAmPmMidnightNoon() {
5065 // Some times on 2015-11-13 (UTC+0).
5066 UDate k000000 = 1447372800000.0;
5067 UDate k000030 = 1447372830000.0;
5068 UDate k003000 = 1447374600000.0;
5069 UDate k060000 = 1447394400000.0;
5070 UDate k120000 = 1447416000000.0;
5071 UDate k180000 = 1447437600000.0;
5072
5073 UErrorCode errorCode = U_ZERO_ERROR;
5074 SimpleDateFormat sdf(UnicodeString(), errorCode);
5075 if (U_FAILURE(errorCode)) {
5076 dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
5077 return;
5078 }
5079 const TimeZone *tz = TimeZone::getGMT();
5080 sdf.setTimeZone(*tz);
5081 UnicodeString out;
5082
5083 // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
5084 // For ICU 57 output of "midnight" is temporarily suppressed.
5085
5086 // Short.
5087 sdf.applyPattern(UnicodeString("hh:mm:ss bbb"));
5088
5089 // assertEquals("hh:mm:ss bbb | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
5090 assertEquals("hh:mm:ss bbb | 00:00:00", "12:00:00 AM", sdf.format(k000000, out.remove()));
5091 assertEquals("hh:mm:ss bbb | 00:00:30", "12:00:30 AM", sdf.format(k000030, out.remove()));
5092 assertEquals("hh:mm:ss bbb | 00:30:00", "12:30:00 AM", sdf.format(k003000, out.remove()));
5093 assertEquals("hh:mm:ss bbb | 06:00:00", "06:00:00 AM", sdf.format(k060000, out.remove()));
5094 assertEquals("hh:mm:ss bbb | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
5095 assertEquals("hh:mm:ss bbb | 18:00:00", "06:00:00 PM", sdf.format(k180000, out.remove()));
5096
5097 sdf.applyPattern(UnicodeString("hh:mm bbb"));
5098
5099 // assertEquals("hh:mm bbb | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
5100 assertEquals("hh:mm bbb | 00:00:00", "12:00 AM", sdf.format(k000000, out.remove()));
5101 // assertEquals("hh:mm bbb | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
5102 assertEquals("hh:mm bbb | 00:00:30", "12:00 AM", sdf.format(k000030, out.remove()));
5103 assertEquals("hh:mm bbb | 00:30:00", "12:30 AM", sdf.format(k003000, out.remove()));
5104
5105 sdf.applyPattern(UnicodeString("hh bbb"));
5106
5107 // assertEquals("hh bbb | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
5108 assertEquals("hh bbb | 00:00:00", "12 AM", sdf.format(k000000, out.remove()));
5109 // assertEquals("hh bbb | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
5110 assertEquals("hh bbb | 00:00:30", "12 AM", sdf.format(k000030, out.remove()));
5111 // assertEquals("hh bbb | 00:30:00", "12 midnight", sdf.format(k003000, out.remove()));
5112 assertEquals("hh bbb | 00:30:00", "12 AM", sdf.format(k003000, out.remove()));
5113
5114 // Wide.
5115 sdf.applyPattern(UnicodeString("hh:mm:ss bbbb"));
5116
5117 // assertEquals("hh:mm:ss bbbb | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
5118 assertEquals("hh:mm:ss bbbb | 00:00:00", "12:00:00 AM", sdf.format(k000000, out.remove()));
5119 assertEquals("hh:mm:ss bbbb | 00:00:30", "12:00:30 AM", sdf.format(k000030, out.remove()));
5120 assertEquals("hh:mm:ss bbbb | 00:30:00", "12:30:00 AM", sdf.format(k003000, out.remove()));
5121 assertEquals("hh:mm:ss bbbb | 06:00:00", "06:00:00 AM", sdf.format(k060000, out.remove()));
5122 assertEquals("hh:mm:ss bbbb | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
5123 assertEquals("hh:mm:ss bbbb | 18:00:00", "06:00:00 PM", sdf.format(k180000, out.remove()));
5124
5125 sdf.applyPattern(UnicodeString("hh:mm bbbb"));
5126
5127 // assertEquals("hh:mm bbbb | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
5128 assertEquals("hh:mm bbbb | 00:00:00", "12:00 AM", sdf.format(k000000, out.remove()));
5129 // assertEquals("hh:mm bbbb | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
5130 assertEquals("hh:mm bbbb | 00:00:30", "12:00 AM", sdf.format(k000030, out.remove()));
5131 assertEquals("hh:mm bbbb | 00:30:00", "12:30 AM", sdf.format(k003000, out.remove()));
5132
5133 sdf.applyPattern(UnicodeString("hh bbbb"));
5134
5135 // assertEquals("hh bbbb | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
5136 assertEquals("hh bbbb | 00:00:00", "12 AM", sdf.format(k000000, out.remove()));
5137 // assertEquals("hh bbbb | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
5138 assertEquals("hh bbbb | 00:00:30", "12 AM", sdf.format(k000030, out.remove()));
5139 // assertEquals("hh bbbb | 00:30:00", "12 midnight", sdf.format(k003000, out.remove()));
5140 assertEquals("hh bbbb | 00:30:00", "12 AM", sdf.format(k003000, out.remove()));
5141
5142 // Narrow.
5143 sdf.applyPattern(UnicodeString("hh:mm:ss bbbbb"));
5144
5145 // assertEquals("hh:mm:ss bbbbb | 00:00:00", "12:00:00 mi", sdf.format(k000000, out.remove()));
5146 assertEquals("hh:mm:ss bbbbb | 00:00:00", "12:00:00 a", sdf.format(k000000, out.remove()));
5147 assertEquals("hh:mm:ss bbbbb | 00:00:30", "12:00:30 a", sdf.format(k000030, out.remove()));
5148 assertEquals("hh:mm:ss bbbbb | 00:30:00", "12:30:00 a", sdf.format(k003000, out.remove()));
5149 assertEquals("hh:mm:ss bbbbb | 06:00:00", "06:00:00 a", sdf.format(k060000, out.remove()));
5150 assertEquals("hh:mm:ss bbbbb | 12:00:00", "12:00:00 n", sdf.format(k120000, out.remove()));
5151 assertEquals("hh:mm:ss bbbbb | 18:00:00", "06:00:00 p", sdf.format(k180000, out.remove()));
5152
5153 sdf.applyPattern(UnicodeString("hh:mm bbbbb"));
5154
5155 // assertEquals("hh:mm bbbbb | 00:00:00", "12:00 mi", sdf.format(k000000, out.remove()));
5156 assertEquals("hh:mm bbbbb | 00:00:00", "12:00 a", sdf.format(k000000, out.remove()));
5157 // assertEquals("hh:mm bbbbb | 00:00:30", "12:00 mi", sdf.format(k000030, out.remove()));
5158 assertEquals("hh:mm bbbbb | 00:00:30", "12:00 a", sdf.format(k000030, out.remove()));
5159 assertEquals("hh:mm bbbbb | 00:30:00", "12:30 a", sdf.format(k003000, out.remove()));
5160
5161 sdf.applyPattern(UnicodeString("hh bbbbb"));
5162
5163 // assertEquals("hh bbbbb | 00:00:00", "12 mi", sdf.format(k000000, out.remove()));
5164 assertEquals("hh bbbbb | 00:00:00", "12 a", sdf.format(k000000, out.remove()));
5165 // assertEquals("hh bbbbb | 00:00:30", "12 mi", sdf.format(k000030, out.remove()));
5166 assertEquals("hh bbbbb | 00:00:30", "12 a", sdf.format(k000030, out.remove()));
5167 // assertEquals("hh bbbbb | 00:30:00", "12 mi", sdf.format(k003000, out.remove()));
5168 assertEquals("hh bbbbb | 00:30:00", "12 a", sdf.format(k003000, out.remove()));
5169 }
5170
TestFlexibleDayPeriod()5171 void DateFormatTest::TestFlexibleDayPeriod() {
5172 // Some times on 2015-11-13 (UTC+0).
5173 UDate k000000 = 1447372800000.0;
5174 UDate k000030 = 1447372830000.0;
5175 UDate k003000 = 1447374600000.0;
5176 UDate k060000 = 1447394400000.0;
5177 UDate k120000 = 1447416000000.0;
5178 UDate k180000 = 1447437600000.0;
5179
5180 UErrorCode errorCode = U_ZERO_ERROR;
5181 SimpleDateFormat sdf(UnicodeString(), errorCode);
5182 if (U_FAILURE(errorCode)) {
5183 dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
5184 return;
5185 }
5186 const TimeZone *tz = TimeZone::getGMT();
5187 sdf.setTimeZone(*tz);
5188 UnicodeString out;
5189
5190 // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
5191 // For ICU 57 output of "midnight" is temporarily suppressed.
5192
5193 // Short.
5194 sdf.applyPattern(UnicodeString("hh:mm:ss BBB"));
5195
5196 // assertEquals("hh:mm:ss BBB | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
5197 assertEquals("hh:mm:ss BBB | 00:00:00", "12:00:00 at night", sdf.format(k000000, out.remove()));
5198 assertEquals("hh:mm:ss BBB | 00:00:30", "12:00:30 at night", sdf.format(k000030, out.remove()));
5199 assertEquals("hh:mm:ss BBB | 00:30:00", "12:30:00 at night", sdf.format(k003000, out.remove()));
5200 assertEquals("hh:mm:ss BBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000, out.remove()));
5201 assertEquals("hh:mm:ss BBB | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
5202 assertEquals("hh:mm:ss BBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000, out.remove()));
5203
5204 sdf.applyPattern(UnicodeString("hh:mm BBB"));
5205
5206 // assertEquals("hh:mm BBB | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
5207 assertEquals("hh:mm BBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
5208 // assertEquals("hh:mm BBB | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
5209 assertEquals("hh:mm BBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
5210 assertEquals("hh:mm BBB | 00:30:00", "12:30 at night", sdf.format(k003000, out.remove()));
5211
5212 sdf.applyPattern(UnicodeString("hh BBB"));
5213
5214 // assertEquals("hh BBB | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
5215 assertEquals("hh BBB | 00:00:30", "12 at night", sdf.format(k000030, out.remove()));
5216 // assertEquals("hh BBB | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
5217 assertEquals("hh BBB | 00:00:30", "12 at night", sdf.format(k000030, out.remove()));
5218 // assertEquals("hh BBB | 00:30:00", "12 midnight", sdf.format(k003000, out.remove()));
5219 assertEquals("hh BBB | 00:30:00", "12 at night", sdf.format(k003000, out.remove()));
5220
5221 // Wide.
5222 sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5223
5224 // assertEquals("hh:mm:ss BBBB | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
5225 assertEquals("hh:mm:ss BBBB | 00:00:00", "12:00:00 at night", sdf.format(k000000, out.remove()));
5226 assertEquals("hh:mm:ss BBBB | 00:00:30", "12:00:30 at night", sdf.format(k000030, out.remove()));
5227 assertEquals("hh:mm:ss BBBB | 00:30:00", "12:30:00 at night", sdf.format(k003000, out.remove()));
5228 assertEquals("hh:mm:ss BBBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000, out.remove()));
5229 assertEquals("hh:mm:ss BBBB | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
5230 assertEquals("hh:mm:ss BBBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000, out.remove()));
5231
5232 sdf.applyPattern(UnicodeString("hh:mm BBBB"));
5233
5234 // assertEquals("hh:mm BBBB | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
5235 assertEquals("hh:mm BBBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
5236 // assertEquals("hh:mm BBBB | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
5237 assertEquals("hh:mm BBBB | 00:00:30", "12:00 at night", sdf.format(k000030, out.remove()));
5238 assertEquals("hh:mm BBBB | 00:30:00", "12:30 at night", sdf.format(k003000, out.remove()));
5239
5240 sdf.applyPattern(UnicodeString("hh BBBB"));
5241
5242 // assertEquals("hh BBBB | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
5243 assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
5244 // assertEquals("hh BBBB | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
5245 assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
5246 // assertEquals("hh BBBB | 00:80:00", "12 midnight", sdf.format(k003000, out.remove()));
5247 assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
5248
5249 // Narrow.
5250 sdf.applyPattern(UnicodeString("hh:mm:ss BBBBB"));
5251
5252 // assertEquals("hh:mm:ss BBBBB | 00:00:00", "12:00:00 mi", sdf.format(k000000, out.remove()));
5253 assertEquals("hh:mm:ss BBBBB | 00:00:00", "12:00:00 at night", sdf.format(k000000, out.remove()));
5254 assertEquals("hh:mm:ss BBBBB | 00:00:30", "12:00:30 at night", sdf.format(k000030, out.remove()));
5255 assertEquals("hh:mm:ss BBBBB | 00:30:00", "12:30:00 at night", sdf.format(k003000, out.remove()));
5256 assertEquals("hh:mm:ss BBBBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000, out.remove()));
5257 assertEquals("hh:mm:ss BBBBB | 12:00:00", "12:00:00 n", sdf.format(k120000, out.remove()));
5258 assertEquals("hh:mm:ss BBBBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000, out.remove()));
5259
5260 sdf.applyPattern(UnicodeString("hh:mm BBBBB"));
5261
5262 // assertEquals("hh:mm BBBBB | 00:00:00", "12:00 mi", sdf.format(k000000, out.remove()));
5263 assertEquals("hh:mm BBBBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
5264 // assertEquals("hh:mm BBBBB | 00:00:30", "12:00 mi", sdf.format(k000030, out.remove()));
5265 assertEquals("hh:mm BBBBB | 00:00:30", "12:00 at night", sdf.format(k000030, out.remove()));
5266 assertEquals("hh:mm BBBBB | 00:30:00", "12:30 at night", sdf.format(k003000, out.remove()));
5267
5268 sdf.applyPattern(UnicodeString("hh BBBBB"));
5269
5270 // assertEquals("hh BBBBB | 00:00:00", "12 mi", sdf.format(k000000, out.remove()));
5271 assertEquals("hh BBBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
5272 // assertEquals("hh BBBBB | 00:00:30", "12 mi", sdf.format(k000030, out.remove()));
5273 assertEquals("hh BBBBB | 00:00:30", "12 at night", sdf.format(k000030, out.remove()));
5274 // assertEquals("hh BBBBB | 00:30:00", "12 mi", sdf.format(k003000, out.remove()));
5275 assertEquals("hh BBBBB | 00:30:00", "12 at night", sdf.format(k003000, out.remove()));
5276 }
5277
TestDayPeriodWithLocales()5278 void DateFormatTest::TestDayPeriodWithLocales() {
5279 // Some times on 2015-11-13 (UTC+0).
5280 UDate k000000 = 1447372800000.0;
5281 UDate k010000 = 1447376400000.0;
5282 UDate k120000 = 1447416000000.0;
5283 UDate k220000 = 1447452000000.0;
5284
5285 UErrorCode errorCode = U_ZERO_ERROR;
5286 const TimeZone *tz = TimeZone::getGMT();
5287 UnicodeString out;
5288
5289 // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
5290 // For ICU 57 output of "midnight" and its localized equivalentns is temporarily suppressed.
5291
5292 // Locale de has a word for midnight, but not noon.
5293 SimpleDateFormat sdf(UnicodeString(), Locale::getGermany(), errorCode);
5294 if (U_FAILURE(errorCode)) {
5295 dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
5296 return;
5297 }
5298 sdf.setTimeZone(*tz);
5299
5300 sdf.applyPattern(UnicodeString("hh:mm:ss bbbb"));
5301
5302 // assertEquals("hh:mm:ss bbbb | 00:00:00 | de", "12:00:00 Mitternacht",
5303 // sdf.format(k000000, out.remove()));
5304 assertEquals("hh:mm:ss bbbb | 00:00:00 | de", "12:00:00 AM",
5305 sdf.format(k000000, out.remove()));
5306 assertEquals("hh:mm:ss bbbb | 12:00:00 | de", "12:00:00 PM",
5307 sdf.format(k120000, out.remove()));
5308
5309 // Locale ee has a rule that wraps around midnight (21h - 4h).
5310 sdf = SimpleDateFormat(UnicodeString(), Locale("ee"), errorCode);
5311 sdf.setTimeZone(*tz);
5312
5313 sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5314
5315 assertEquals("hh:mm:ss BBBB | 22:00:00 | ee", UnicodeString("10:00:00 z\\u00E3").unescape(),
5316 sdf.format(k220000, out.remove()));
5317 assertEquals("hh:mm:ss BBBB | 00:00:00 | ee", UnicodeString("12:00:00 z\\u00E3").unescape(),
5318 sdf.format(k000000, out.remove()));
5319 assertEquals("hh:mm:ss BBBB | 01:00:00 | ee", UnicodeString("01:00:00 z\\u00E3").unescape(),
5320 sdf.format(k010000, out.remove()));
5321
5322 // Locale root has rules for AM/PM only.
5323 sdf = SimpleDateFormat(UnicodeString(), Locale("root"), errorCode);
5324 sdf.setTimeZone(*tz);
5325
5326 sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5327
5328 assertEquals("hh:mm:ss BBBB | 00:00:00 | root", "12:00:00 AM",
5329 sdf.format(k000000, out.remove()));
5330 assertEquals("hh:mm:ss BBBB | 12:00:00 | root", "12:00:00 PM",
5331 sdf.format(k120000, out.remove()));
5332
5333 // Empty string should behave exactly as root.
5334 sdf = SimpleDateFormat(UnicodeString(), Locale(""), errorCode);
5335 sdf.setTimeZone(*tz);
5336
5337 sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5338
5339 assertEquals("hh:mm:ss BBBB | 00:00:00 | \"\" (root)", "12:00:00 AM",
5340 sdf.format(k000000, out.remove()));
5341 assertEquals("hh:mm:ss BBBB | 12:00:00 | \"\" (root)", "12:00:00 PM",
5342 sdf.format(k120000, out.remove()));
5343
5344 // Locale en_US should fall back to en.
5345 sdf = SimpleDateFormat(UnicodeString(), Locale("en_US"), errorCode);
5346 sdf.setTimeZone(*tz);
5347
5348 sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5349
5350 // assertEquals("hh:mm:ss BBBB | 00:00:00 | en_US", "12:00:00 midnight",
5351 // sdf.format(k000000, out.remove()));
5352 assertEquals("hh:mm:ss BBBB | 00:00:00 | en_US", "12:00:00 at night",
5353 sdf.format(k000000, out.remove()));
5354 assertEquals("hh:mm:ss BBBB | 01:00:00 | en_US", "01:00:00 at night",
5355 sdf.format(k010000, out.remove()));
5356 assertEquals("hh:mm:ss BBBB | 12:00:00 | en_US", "12:00:00 noon",
5357 sdf.format(k120000, out.remove()));
5358
5359 // Locale es_CO should not fall back to es and should have a
5360 // different string for 1 in the morning.
5361 // (es_CO: "de la manana" (first n has a tilde) vs. es: "de la madrugada")
5362 sdf = SimpleDateFormat(UnicodeString(), Locale("es_CO"), errorCode);
5363 sdf.setTimeZone(*tz);
5364
5365 sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5366 assertEquals("hh:mm:ss BBBB | 01:00:00 | es_CO", u"01:00:00 de la mañana",
5367 sdf.format(k010000, out.remove()));
5368
5369 sdf = SimpleDateFormat(UnicodeString(), Locale("es"), errorCode);
5370 sdf.setTimeZone(*tz);
5371
5372 sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5373 assertEquals("hh:mm:ss BBBB | 01:00:00 | es", "01:00:00 de la madrugada",
5374 sdf.format(k010000, out.remove()));
5375
5376 // #13215: for locales with keywords, check hang in DayPeriodRules""getInstance(const Locale, ...),
5377 // which is called in SimpleDateFormat::format for patterns that include 'B'.
5378 sdf = SimpleDateFormat(UnicodeString(), Locale("en@calendar=buddhist"), errorCode);
5379 sdf.setTimeZone(*tz);
5380
5381 sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
5382 assertEquals("hh:mm:ss BBBB | 01:00:00 | en@calendar=buddhist", "01:00:00 at night",
5383 sdf.format(k010000, out.remove()));
5384 }
5385
TestMinuteSecondFieldsInOddPlaces()5386 void DateFormatTest::TestMinuteSecondFieldsInOddPlaces() {
5387 // Some times on 2015-11-13 (UTC+0).
5388 UDate k000000 = 1447372800000.0;
5389 UDate k000030 = 1447372830000.0;
5390 UDate k003000 = 1447374600000.0;
5391 UDate k060030 = 1447394430000.0;
5392 UDate k063000 = 1447396200000.0;
5393
5394 UErrorCode errorCode = U_ZERO_ERROR;
5395 const TimeZone *tz = TimeZone::getGMT();
5396 UnicodeString out;
5397
5398 // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
5399 // For ICU 57 output of "midnight" is temporarily suppressed.
5400
5401 // Seconds field is not present.
5402
5403 // Apply pattern through constructor to make sure parsePattern() is called during initialization.
5404 SimpleDateFormat sdf(UnicodeString("hh:mm 'ss' bbbb"), errorCode);
5405 if (U_FAILURE(errorCode)) {
5406 dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
5407 return;
5408 }
5409 sdf.setTimeZone(*tz);
5410
5411 // assertEquals("hh:mm 'ss' bbbb | 00:00:30", "12:00 ss midnight",
5412 // sdf.format(k000030, out.remove()));
5413 assertEquals("hh:mm 'ss' bbbb | 00:00:30", "12:00 ss AM",
5414 sdf.format(k000030, out.remove()));
5415 assertEquals("hh:mm 'ss' bbbb | 06:00:30", "06:00 ss AM",
5416 sdf.format(k060030, out.remove()));
5417
5418 sdf.applyPattern(UnicodeString("hh:mm 'ss' BBBB"));
5419
5420 // assertEquals("hh:mm 'ss' BBBB | 00:00:30", "12:00 ss midnight",
5421 // sdf.format(k000030, out.remove()));
5422 assertEquals("hh:mm 'ss' BBBB | 00:00:30", "12:00 ss at night",
5423 sdf.format(k000030, out.remove()));
5424 assertEquals("hh:mm 'ss' BBBB | 06:00:30", "06:00 ss in the morning",
5425 sdf.format(k060030, out.remove()));
5426
5427 // Minutes field is not present.
5428 sdf.applyPattern(UnicodeString("hh 'mm ss' bbbb"));
5429
5430 // assertEquals("hh 'mm ss' bbbb | 00:30:00", "12 mm ss midnight",
5431 // sdf.format(k003000, out.remove()));
5432 assertEquals("hh 'mm ss' bbbb | 00:30:00", "12 mm ss AM",
5433 sdf.format(k003000, out.remove()));
5434 assertEquals("hh 'mm ss' bbbb | 06:30:00", "06 mm ss AM",
5435 sdf.format(k063000, out.remove()));
5436
5437 sdf.applyPattern(UnicodeString("hh 'mm ss' BBBB"));
5438
5439 // assertEquals("hh 'mm ss' BBBB | 00:30:00", "12 mm ss midnight",
5440 // sdf.format(k003000, out.remove()));
5441 assertEquals("hh 'mm ss' BBBB | 00:30:00", "12 mm ss at night",
5442 sdf.format(k003000, out.remove()));
5443 assertEquals("hh 'mm ss' BBBB | 06:30:00", "06 mm ss in the morning",
5444 sdf.format(k063000, out.remove()));
5445
5446 // Minutes and seconds fields appear after day periods.
5447 sdf.applyPattern(UnicodeString("bbbb hh:mm:ss"));
5448
5449 // assertEquals("bbbb hh:mm:ss | 00:00:00", "midnight 12:00:00",
5450 // sdf.format(k000000, out.remove()));
5451 assertEquals("bbbb hh:mm:ss | 00:00:00", "AM 12:00:00",
5452 sdf.format(k000000, out.remove()));
5453 assertEquals("bbbb hh:mm:ss | 00:00:30", "AM 12:00:30",
5454 sdf.format(k000030, out.remove()));
5455 assertEquals("bbbb hh:mm:ss | 00:30:00", "AM 12:30:00",
5456 sdf.format(k003000, out.remove()));
5457
5458 sdf.applyPattern(UnicodeString("BBBB hh:mm:ss"));
5459
5460 // assertEquals("BBBB hh:mm:ss | 00:00:00", "midnight 12:00:00",
5461 // sdf.format(k000000, out.remove()));
5462 assertEquals("BBBB hh:mm:ss | 00:00:00", "at night 12:00:00",
5463 sdf.format(k000000, out.remove()));
5464 assertEquals("BBBB hh:mm:ss | 00:00:30", "at night 12:00:30",
5465 sdf.format(k000030, out.remove()));
5466 assertEquals("BBBB hh:mm:ss | 00:30:00", "at night 12:30:00",
5467 sdf.format(k003000, out.remove()));
5468
5469 // Confirm applyPattern() reparses the pattern string.
5470 sdf.applyPattern(UnicodeString("BBBB hh"));
5471 // assertEquals("BBBB hh | 00:00:30", "midnight 12",
5472 // sdf.format(k000030, out.remove()));
5473 assertEquals("BBBB hh | 00:00:30", "at night 12",
5474 sdf.format(k000030, out.remove()));
5475
5476 sdf.applyPattern(UnicodeString("BBBB hh:mm:'ss'"));
5477 // assertEquals("BBBB hh:mm:'ss' | 00:00:30", "midnight 12:00:ss",
5478 // sdf.format(k000030, out.remove()));
5479 assertEquals("BBBB hh | 00:00:30", "at night 12:00:ss",
5480 sdf.format(k000030, out.remove()));
5481
5482 sdf.applyPattern(UnicodeString("BBBB hh:mm:ss"));
5483 assertEquals("BBBB hh:mm:ss | 00:00:30", "at night 12:00:30",
5484 sdf.format(k000030, out.remove()));
5485 }
5486
TestDayPeriodParsing()5487 void DateFormatTest::TestDayPeriodParsing() {
5488 // Some times on 2015-11-13 (UTC+0).
5489 UDate k000000 = 1447372800000.0;
5490 UDate k003700 = 1447375020000.0;
5491 UDate k010000 = 1447376400000.0;
5492 UDate k013000 = 1447378200000.0;
5493 UDate k030000 = 1447383600000.0;
5494 UDate k090000 = 1447405200000.0;
5495 UDate k120000 = 1447416000000.0;
5496 UDate k130000 = 1447419600000.0;
5497 UDate k133700 = 1447421820000.0;
5498 UDate k150000 = 1447426800000.0;
5499 UDate k190000 = 1447441200000.0;
5500 UDate k193000 = 1447443000000.0;
5501 UDate k200000 = 1447444800000.0;
5502 UDate k210000 = 1447448400000.0;
5503
5504 UErrorCode errorCode = U_ZERO_ERROR;
5505 SimpleDateFormat sdf(UnicodeString(), errorCode);
5506 if (U_FAILURE(errorCode)) {
5507 dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
5508 return;
5509 }
5510 const TimeZone *tz = TimeZone::getGMT();
5511 sdf.setTimeZone(*tz);
5512 UnicodeString out;
5513
5514 // 'B' -- flexible day periods
5515 // A day period on its own parses to the center of that period.
5516 sdf.applyPattern(UnicodeString("yyyy-MM-dd B"));
5517 assertEquals("yyyy-MM-dd B | 2015-11-13 midnight",
5518 k000000, sdf.parse(UnicodeString("2015-11-13 midnight"), errorCode));
5519 assertEquals("yyyy-MM-dd B | 2015-11-13 noon",
5520 k120000, sdf.parse(UnicodeString("2015-11-13 noon"), errorCode));
5521 assertEquals("yyyy-MM-dd B | 2015-11-13 in the afternoon",
5522 k150000, sdf.parse(UnicodeString("2015-11-13 in the afternoon"), errorCode));
5523 assertEquals("yyyy-MM-dd B | 2015-11-13 in the evening",
5524 k193000, sdf.parse(UnicodeString("2015-11-13 in the evening"), errorCode));
5525 assertEquals("yyyy-MM-dd B | 2015-11-13 at night",
5526 k013000, sdf.parse(UnicodeString("2015-11-13 at night"), errorCode));
5527
5528 // If time and day period are consistent with each other then time is parsed accordingly.
5529 sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm B"));
5530 assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 12:00 midnight",
5531 k000000, sdf.parse(UnicodeString("2015-11-13 12:00 midnight"), errorCode));
5532 assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 12:00 noon",
5533 k120000, sdf.parse(UnicodeString("2015-11-13 12:00 noon"), errorCode));
5534 assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 01:00 at night",
5535 k010000, sdf.parse(UnicodeString("2015-11-13 01:00 at night"), errorCode));
5536 assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 01:00 in the afternoon",
5537 k130000, sdf.parse(UnicodeString("2015-11-13 01:00 in the afternoon"), errorCode));
5538 assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 09:00 in the morning",
5539 k090000, sdf.parse(UnicodeString("2015-11-13 09:00 in the morning"), errorCode));
5540 assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 09:00 at night",
5541 k210000, sdf.parse(UnicodeString("2015-11-13 09:00 at night"), errorCode));
5542
5543 // If the hour is 13 thru 23 then day period has no effect on time (since time is assumed
5544 // to be in 24-hour format).
5545 sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm B"));
5546 assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 midnight",
5547 k133700, sdf.parse(UnicodeString("2015-11-13 13:37 midnight"), errorCode));
5548 assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 noon",
5549 k133700, sdf.parse(UnicodeString("2015-11-13 13:37 noon"), errorCode));
5550 assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 at night",
5551 k133700, sdf.parse(UnicodeString("2015-11-13 13:37 at night"), errorCode));
5552 assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 in the afternoon",
5553 k133700, sdf.parse(UnicodeString("2015-11-13 13:37 in the afternoon"), errorCode));
5554 assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 in the morning",
5555 k133700, sdf.parse(UnicodeString("2015-11-13 13:37 in the morning"), errorCode));
5556 assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 at night",
5557 k133700, sdf.parse(UnicodeString("2015-11-13 13:37 at night"), errorCode));
5558
5559 // Hour 0 is synonymous with hour 12 when parsed with 'h'.
5560 // This unfortunately means we have to tolerate "0 noon" as it's synonymous with "12 noon".
5561 sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm B"));
5562 assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 00:00 midnight",
5563 k000000, sdf.parse(UnicodeString("2015-11-13 00:00 midnight"), errorCode));
5564 assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 00:00 noon",
5565 k120000, sdf.parse(UnicodeString("2015-11-13 00:00 noon"), errorCode));
5566
5567 // But when parsed with 'H', 0 indicates a 24-hour time, therefore we disregard the day period.
5568 sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm B"));
5569 assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 midnight",
5570 k003700, sdf.parse(UnicodeString("2015-11-13 00:37 midnight"), errorCode));
5571 assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 noon",
5572 k003700, sdf.parse(UnicodeString("2015-11-13 00:37 noon"), errorCode));
5573 assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 at night",
5574 k003700, sdf.parse(UnicodeString("2015-11-13 00:37 at night"), errorCode));
5575 assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 in the afternoon",
5576 k003700, sdf.parse(UnicodeString("2015-11-13 00:37 in the afternoon"), errorCode));
5577 assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 in the morning",
5578 k003700, sdf.parse(UnicodeString("2015-11-13 00:37 in the morning"), errorCode));
5579 assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 at night",
5580 k003700, sdf.parse(UnicodeString("2015-11-13 00:37 at night"), errorCode));
5581
5582 // Even when parsed with 'H', hours 1 thru 12 are considered 12-hour time and takes
5583 // day period into account in parsing.
5584 sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm B"));
5585 assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 12:00 midnight",
5586 k000000, sdf.parse(UnicodeString("2015-11-13 12:00 midnight"), errorCode));
5587 assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 12:00 noon",
5588 k120000, sdf.parse(UnicodeString("2015-11-13 12:00 noon"), errorCode));
5589 assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 01:00 at night",
5590 k010000, sdf.parse(UnicodeString("2015-11-13 01:00 at night"), errorCode));
5591 assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 01:00 in the afternoon",
5592 k130000, sdf.parse(UnicodeString("2015-11-13 01:00 in the afternoon"), errorCode));
5593 assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 09:00 in the morning",
5594 k090000, sdf.parse(UnicodeString("2015-11-13 09:00 in the morning"), errorCode));
5595 assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 09:00 at night",
5596 k210000, sdf.parse(UnicodeString("2015-11-13 09:00 at night"), errorCode));
5597
5598 // If a 12-hour time and the day period don't agree with each other, time is parsed as close
5599 // to the given day period as possible.
5600 sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm B"));
5601
5602 // AFTERNOON1 is [12, 18), but "7 in the afternoon" parses to 19:00.
5603 assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 07:00 in the afternoon",
5604 k190000, sdf.parse(UnicodeString("2015-11-13 07:00 in the afternoon"), errorCode));
5605 // NIGHT1 is [21, 6), but "8 at night" parses to 20:00.
5606 assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 08:00 at night",
5607 k200000, sdf.parse(UnicodeString("2015-11-13 08:00 at night"), errorCode));
5608
5609 // 'b' -- fixed day periods (AM, PM, midnight, noon)
5610 // On their own, "midnight" parses to 00:00 and "noon" parses to 12:00.
5611 // AM and PM are handled by the 'a' parser (which doesn't handle this case well).
5612 sdf.applyPattern(UnicodeString("yyyy-MM-dd b"));
5613 assertEquals("yyyy-MM-dd b | 2015-11-13 midnight",
5614 k000000, sdf.parse(UnicodeString("2015-11-13 midnight"), errorCode));
5615 assertEquals("yyyy-MM-dd b | 2015-11-13 noon",
5616 k120000, sdf.parse(UnicodeString("2015-11-13 noon"), errorCode));
5617
5618 // For 12-hour times, AM and PM should be parsed as if with pattern character 'a'.
5619 sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm b"));
5620 assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 01:00 AM",
5621 k010000, sdf.parse(UnicodeString("2015-11-13 01:00 AM"), errorCode));
5622 assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 01:00 PM",
5623 k130000, sdf.parse(UnicodeString("2015-11-13 01:00 PM"), errorCode));
5624
5625 // 12 midnight parses to 00:00, and 12 noon parses to 12:00.
5626 assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 12:00 midnight",
5627 k000000, sdf.parse(UnicodeString("2015-11-13 12:00 midnight"), errorCode));
5628 assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 12:00 noon",
5629 k120000, sdf.parse(UnicodeString("2015-11-13 12:00 noon"), errorCode));
5630
5631 // Hours 13-23 indicate 24-hour time so we disregard "midnight" or "noon".
5632 // Again, AM and PM are handled by the 'a' parser which doesn't handle this case well.
5633 sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm b"));
5634 assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 13:37 midnight",
5635 k133700, sdf.parse(UnicodeString("2015-11-13 13:37 midnight"), errorCode));
5636 assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 13:37 noon",
5637 k133700, sdf.parse(UnicodeString("2015-11-13 13:37 noon"), errorCode));
5638
5639 // Hour 0 is synonymous with hour 12 when parsed with 'h'.
5640 // Again, this means we have to tolerate "0 noon" as it's synonymous with "12 noon".
5641 sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm b"));
5642 assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 00:00 midnight",
5643 k000000, sdf.parse(UnicodeString("2015-11-13 00:00 midnight"), errorCode));
5644 assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 00:00 noon",
5645 k120000, sdf.parse(UnicodeString("2015-11-13 00:00 noon"), errorCode));
5646
5647 // With 'H' though 0 indicates a 24-hour time, therefore we disregard the day period.
5648 sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm b"));
5649 assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 00:37 midnight",
5650 k003700, sdf.parse(UnicodeString("2015-11-13 00:37 midnight"), errorCode));
5651 assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 00:37 noon",
5652 k003700, sdf.parse(UnicodeString("2015-11-13 00:37 noon"), errorCode));
5653
5654 // If "midnight" or "noon" is parsed with a 12-hour time other than 12:00, choose
5655 // the version that's closer to the period given.
5656 sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm b"));
5657 assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 03:00 midnight",
5658 k030000, sdf.parse(UnicodeString("2015-11-13 03:00 midnight"), errorCode));
5659 assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 03:00 noon",
5660 k150000, sdf.parse(UnicodeString("2015-11-13 03:00 noon"), errorCode));
5661 }
5662
TestParseRegression13744()5663 void DateFormatTest::TestParseRegression13744() {
5664 LocalPointer<DateFormat> dfmt(DateFormat::createDateTimeInstance(
5665 DateFormat::SHORT, DateFormat::SHORT, Locale("en", "US")));
5666 if (dfmt.isNull()) {
5667 dataerrln("DateFormat::createDateTimeInstance() failed");
5668 return;
5669 }
5670 ParsePosition pos(0);
5671 UnicodeString inDate("4/27/18");
5672 dfmt->parse(inDate, pos);
5673 assertEquals("Error index", inDate.length(), pos.getErrorIndex());
5674 }
5675
TestAdoptCalendarLeak()5676 void DateFormatTest::TestAdoptCalendarLeak() {
5677 UErrorCode status = U_ZERO_ERROR;
5678 // This test relies on the locale fullName exceeding ULOC_FULLNAME_CAPACITY
5679 // in order for setKeywordValue to fail.
5680 Calendar* cal = Calendar::createInstance(status);
5681 ASSERT_OK(status);
5682 SimpleDateFormat sdf(
5683 "d.M.y",
5684 Locale("de__POSIX@colstrength=primary;currency=eur;em=default;"
5685 "hours=h23;lb=strict;lw=normal;measure=metric;numbers=latn;"
5686 "rg=atzzzz;sd=atat1;ss=none;timezone=Europe/Vienna"),
5687 status);
5688 // ASSERT_OK(status); Please do NOT add ASSERT_OK here. The point of this
5689 // test is to ensure sdf.adoptCalendar won't leak AFTER the above FAILED.
5690 // If the following caused crash we should fix the implementation not change
5691 // this test.
5692 sdf.adoptCalendar(cal);
5693 }
5694
5695 /**
5696 * Test that 'a' and 'B' fields are not duplicated in the field position iterator.
5697 */
Test20741_ABFields()5698 void DateFormatTest::Test20741_ABFields() {
5699 IcuTestErrorCode status(*this, "Test20741_ABFields");
5700
5701 const char16_t timeZone[] = u"PST8PDT";
5702
5703 UnicodeString skeletons[] = {u"EEEEEBBBBB", u"EEEEEbbbbb"};
5704
5705 for (int32_t j = 0; j < 2; j++) {
5706 UnicodeString skeleton = skeletons[j];
5707
5708 int32_t count = 0;
5709 const Locale* locales = Locale::getAvailableLocales(count);
5710 for (int32_t i = 0; i < count; i++) {
5711 if (quick && (i % 17) != 0) { continue; }
5712
5713 const Locale locale = locales[i];
5714 LocalPointer<DateTimePatternGenerator> gen(DateTimePatternGenerator::createInstance(locale, status));
5715 UnicodeString pattern = gen->getBestPattern(skeleton, status);
5716
5717 SimpleDateFormat dateFormat(pattern, locale, status);
5718 FieldPositionIterator fpositer;
5719 UnicodeString result;
5720 LocalPointer<Calendar> calendar(Calendar::createInstance(TimeZone::createTimeZone(timeZone), status));
5721 calendar->setTime(UDate(0), status);
5722 dateFormat.format(*calendar, result, &fpositer, status);
5723
5724 FieldPosition curFieldPosition;
5725 FieldPosition lastFieldPosition;
5726 lastFieldPosition.setBeginIndex(-1);
5727 lastFieldPosition.setEndIndex(-1);
5728 while(fpositer.next(curFieldPosition)) {
5729 assertFalse("Field missing on pattern", pattern.indexOf(PATTERN_CHARS[curFieldPosition.getField()]) == -1);
5730 if (curFieldPosition.getBeginIndex() == lastFieldPosition.getBeginIndex() && curFieldPosition.getEndIndex() == lastFieldPosition.getEndIndex()) {
5731 assertEquals("Different fields at same position", PATTERN_CHARS[curFieldPosition.getField()], PATTERN_CHARS[lastFieldPosition.getField()]);
5732 }
5733
5734 lastFieldPosition = curFieldPosition;
5735 }
5736 }
5737 }
5738 }
5739
Test22023_UTCWithMinusZero()5740 void DateFormatTest::Test22023_UTCWithMinusZero() {
5741 IcuTestErrorCode status(*this, "Test22023_UTCWithMinusZero");
5742 Locale locale("en");
5743 SimpleDateFormat fmt("h a", locale, status);
5744 ASSERT_OK(status);
5745 fmt.adoptCalendar(Calendar::createInstance(
5746 TimeZone::createTimeZone("UTC"), locale, status));
5747 ASSERT_OK(status);
5748 FieldPositionIterator fp_iter;
5749 icu::UnicodeString formatted;
5750 // very small negative value in double cause it to be -0
5751 // internally and trigger the assertion and bug.
5752 fmt.format(-1e-9, formatted, &fp_iter, status);
5753 ASSERT_OK(status);
5754 }
5755
TestNumericFieldStrictParse()5756 void DateFormatTest::TestNumericFieldStrictParse() {
5757 static const struct {
5758 const char* localeID;
5759 const char16_t* const pattern;
5760 const char16_t* const text;
5761 int32_t pos; // final parsed position
5762 UCalendarDateFields field1;
5763 int32_t value1;
5764 UCalendarDateFields field2;
5765 int32_t value2;
5766 } TESTDATA[] = {
5767 // Ticket #22337
5768 {"en_US", u"MM/dd/yyyy", u"1/1/2023", 8, UCAL_MONTH, UCAL_JANUARY, UCAL_DAY_OF_MONTH, 1},
5769 // Ticket #22259
5770 {"en_US", u"dd-MM-uuuu", u"1-01-2023", 9, UCAL_MONTH, UCAL_JANUARY, UCAL_DAY_OF_MONTH, 1},
5771 {"en_US", u"dd-MM-uuuu", u"01-01-223", 9, UCAL_DAY_OF_MONTH, 1, UCAL_EXTENDED_YEAR, 223},
5772 };
5773 for (size_t i = 0; i < UPRV_LENGTHOF(TESTDATA); i++) {
5774 UErrorCode status = U_ZERO_ERROR;
5775 char pbuf[64];
5776 char tbuf[64];
5777
5778 Locale locale = Locale::createFromName(TESTDATA[i].localeID);
5779 LocalPointer<SimpleDateFormat> sdfmt(new SimpleDateFormat(UnicodeString(TESTDATA[i].pattern), locale, status));
5780 if (U_FAILURE(status)) {
5781 u_austrncpy(pbuf, TESTDATA[i].pattern, sizeof(pbuf));
5782 dataerrln("Fail in new SimpleDateFormat locale %s pattern %s: %s",
5783 TESTDATA[i].localeID, pbuf, u_errorName(status));
5784 continue;
5785 }
5786 LocalPointer<Calendar> cal(Calendar::createInstance(*TimeZone::getGMT(), locale, status));
5787 if (U_FAILURE(status)) {
5788 dataerrln("Fail in Calendar::createInstance locale %s: %s",
5789 TESTDATA[i].localeID, u_errorName(status));
5790 continue;
5791 }
5792 cal->clear();
5793 //cal->set(2023, 0, 1);
5794 ParsePosition ppos(0);
5795 sdfmt->setLenient(false);
5796 sdfmt->parse(UnicodeString(TESTDATA[i].text), *cal, ppos);
5797
5798 u_austrncpy(pbuf, TESTDATA[i].pattern, sizeof(pbuf));
5799 u_austrncpy(tbuf, TESTDATA[i].text, sizeof(tbuf));
5800 if (ppos.getIndex() != TESTDATA[i].pos) {
5801 errln("SimpleDateFormat::parse locale %s pattern %s: expected pos %d, got %d, errIndex %d",
5802 TESTDATA[i].localeID, pbuf, TESTDATA[i].pos, ppos.getIndex(), ppos.getErrorIndex());
5803 continue;
5804 }
5805 if (TESTDATA[i].field1 < UCAL_FIELD_COUNT) {
5806 int32_t value = cal->get(TESTDATA[i].field1, status);
5807 if (U_FAILURE(status)) {
5808 errln("Calendar::get locale %s pattern %s field %d: %s",
5809 TESTDATA[i].localeID, pbuf, TESTDATA[i].field1, u_errorName(status));
5810 } else if (value != TESTDATA[i].value1) {
5811 errln("Calendar::get locale %s pattern %s field %d: expected value %d, got %d",
5812 TESTDATA[i].localeID, pbuf, TESTDATA[i].field1, TESTDATA[i].value1, value);
5813 }
5814 }
5815 status = U_ZERO_ERROR;
5816 if (TESTDATA[i].field2 < UCAL_FIELD_COUNT) {
5817 int32_t value = cal->get(TESTDATA[i].field2, status);
5818 if (U_FAILURE(status)) {
5819 errln("Calendar::get locale %s pattern %s field %d: %s",
5820 TESTDATA[i].localeID, pbuf, TESTDATA[i].field2, u_errorName(status));
5821 } else if (value != TESTDATA[i].value2) {
5822 errln("Calendar::get locale %s pattern %s field %d: expected value %d, got %d",
5823 TESTDATA[i].localeID, pbuf, TESTDATA[i].field2, TESTDATA[i].value2, value);
5824 }
5825 }
5826 }
5827 }
5828
5829 #endif /* #if !UCONFIG_NO_FORMATTING */
5830
5831 //eof
5832