+typedef struct {
+ const char * localeStr;
+ UBool lenient;
+ UBool expectFail;
+ UnicodeString datePattern;
+ UnicodeString dateString;
+} NumAsStringItem;
+
+void DateFormatTest::TestNumberAsStringParsing()
+{
+ const NumAsStringItem items[] = {
+ // loc lenient fail? datePattern dateString
+ { "", FALSE, TRUE, UnicodeString("y MMMM d HH:mm:ss"), UnicodeString("2009 7 14 08:43:57") },
+ { "", TRUE, FALSE, UnicodeString("y MMMM d HH:mm:ss"), UnicodeString("2009 7 14 08:43:57") },
+ { "en", FALSE, FALSE, UnicodeString("MMM d, y"), UnicodeString("Jul 14, 2009") },
+ { "en", TRUE, FALSE, UnicodeString("MMM d, y"), UnicodeString("Jul 14, 2009") },
+ { "en", FALSE, TRUE, UnicodeString("MMM d, y"), UnicodeString("7 14, 2009") },
+ { "en", TRUE, FALSE, UnicodeString("MMM d, y"), UnicodeString("7 14, 2009") },
+ { "ja", FALSE, FALSE, UnicodeString("yyyy/MM/dd"), UnicodeString("2009/07/14") },
+ { "ja", TRUE, FALSE, UnicodeString("yyyy/MM/dd"), UnicodeString("2009/07/14") },
+ //{ "ja", FALSE, FALSE, UnicodeString("yyyy/MMMMM/d"), UnicodeString("2009/7/14") }, // #8860 covers test failure
+ { "ja", TRUE, FALSE, UnicodeString("yyyy/MMMMM/d"), UnicodeString("2009/7/14") },
+ { "ja", FALSE, FALSE, CharsToUnicodeString("y\\u5E74M\\u6708d\\u65E5"), CharsToUnicodeString("2009\\u5E747\\u670814\\u65E5") },
+ { "ja", TRUE, FALSE, CharsToUnicodeString("y\\u5E74M\\u6708d\\u65E5"), CharsToUnicodeString("2009\\u5E747\\u670814\\u65E5") },
+ { "ja", FALSE, FALSE, CharsToUnicodeString("y\\u5E74MMMd\\u65E5"), CharsToUnicodeString("2009\\u5E747\\u670814\\u65E5") },
+ { "ja", TRUE, FALSE, CharsToUnicodeString("y\\u5E74MMMd\\u65E5"), CharsToUnicodeString("2009\\u5E747\\u670814\\u65E5") }, // #8820 fixes test failure
+ { "ko", FALSE, FALSE, UnicodeString("yyyy. M. d."), UnicodeString("2009. 7. 14.") },
+ { "ko", TRUE, FALSE, UnicodeString("yyyy. M. d."), UnicodeString("2009. 7. 14.") },
+ { "ko", FALSE, FALSE, UnicodeString("yyyy. MMMMM d."), CharsToUnicodeString("2009. 7\\uC6D4 14.") },
+ { "ko", TRUE, FALSE, UnicodeString("yyyy. MMMMM d."), CharsToUnicodeString("2009. 7\\uC6D4 14.") }, // #8820 fixes test failure
+ { "ko", FALSE, FALSE, CharsToUnicodeString("y\\uB144 M\\uC6D4 d\\uC77C"), CharsToUnicodeString("2009\\uB144 7\\uC6D4 14\\uC77C") },
+ { "ko", TRUE, FALSE, CharsToUnicodeString("y\\uB144 M\\uC6D4 d\\uC77C"), CharsToUnicodeString("2009\\uB144 7\\uC6D4 14\\uC77C") },
+ { "ko", FALSE, FALSE, CharsToUnicodeString("y\\uB144 MMM d\\uC77C"), CharsToUnicodeString("2009\\uB144 7\\uC6D4 14\\uC77C") },
+ { "ko", TRUE, FALSE, CharsToUnicodeString("y\\uB144 MMM d\\uC77C"), CharsToUnicodeString("2009\\uB144 7\\uC6D4 14\\uC77C") }, // #8820 fixes test failure
+ { NULL, FALSE, FALSE, UnicodeString(""), UnicodeString("") }
+ };
+ const NumAsStringItem * itemPtr;
+ for (itemPtr = items; itemPtr->localeStr != NULL; itemPtr++ ) {
+ Locale locale = Locale::createFromName(itemPtr->localeStr);
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat *formatter = new SimpleDateFormat(itemPtr->datePattern, locale, status);
+ if (formatter == NULL || U_FAILURE(status)) {
+ dataerrln("Unable to create SimpleDateFormat - %s", u_errorName(status));
+ return;
+ }
+
+ formatter->setLenient(itemPtr->lenient);
+ UDate date1 = formatter->parse(itemPtr->dateString, status);
+ if (U_FAILURE(status)) {
+ if (!itemPtr->expectFail) {
+ errln("FAIL, err when expected success: Locale \"" + UnicodeString(itemPtr->localeStr) + "\", lenient " + itemPtr->lenient +
+ ": using pattern \"" + itemPtr->datePattern + "\", could not parse \"" + itemPtr->dateString + "\"; err: " + u_errorName(status) );
+ }
+ } else if (itemPtr->expectFail) {
+ errln("FAIL, expected err but got none: Locale \"" + UnicodeString(itemPtr->localeStr) + "\", lenient " + itemPtr->lenient +
+ ": using pattern \"" + itemPtr->datePattern + "\", did parse \"" + itemPtr->dateString + "\"." );
+ } else if (!itemPtr->lenient) {
+ UnicodeString formatted;
+ formatter->format(date1, formatted);
+ if (formatted != itemPtr->dateString) {
+ errln("FAIL, mismatch formatting parsed date: Locale \"" + UnicodeString(itemPtr->localeStr) + "\", lenient " + itemPtr->lenient +
+ ": using pattern \"" + itemPtr->datePattern + "\", did parse \"" + itemPtr->dateString + "\", formatted result \"" + formatted + "\".");
+ }
+ }
+
+ delete formatter;
+ }
+}
+
+void DateFormatTest::TestISOEra() {
+
+ const char* data[] = {
+ // input, output
+ "BC 4004-10-23T07:00:00Z", "BC 4004-10-23T07:00:00Z",
+ "AD 4004-10-23T07:00:00Z", "AD 4004-10-23T07:00:00Z",
+ "-4004-10-23T07:00:00Z" , "BC 4005-10-23T07:00:00Z",
+ "4004-10-23T07:00:00Z" , "AD 4004-10-23T07:00:00Z",
+ };
+
+ int32_t numData = 8;
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ // create formatter
+ SimpleDateFormat *fmt1 = new SimpleDateFormat(UnicodeString("GGG yyyy-MM-dd'T'HH:mm:ss'Z"), status);
+ failure(status, "new SimpleDateFormat", TRUE);
+ if (status == U_MISSING_RESOURCE_ERROR) {
+ if (fmt1 != NULL) {
+ delete fmt1;
+ }
+ return;
+ }
+ for(int i=0; i < numData; i+=2) {
+ // create input string
+ UnicodeString in = data[i];
+
+ // parse string to date
+ UDate dt1 = fmt1->parse(in, status);
+ failure(status, "fmt->parse", TRUE);
+
+ // format date back to string
+ UnicodeString out;
+ out = fmt1->format(dt1, out);
+ logln(out);
+
+ // check that roundtrip worked as expected
+ UnicodeString expected = data[i+1];
+ if (out != expected) {
+ dataerrln((UnicodeString)"FAIL: " + in + " -> " + out + " expected -> " + expected);
+ }
+ }
+
+ delete fmt1;
+}
+void DateFormatTest::TestFormalChineseDate() {
+
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString pattern ("y\\u5e74M\\u6708d\\u65e5", -1, US_INV );
+ pattern = pattern.unescape();
+ UnicodeString override ("y=hanidec;M=hans;d=hans", -1, US_INV );
+
+ // create formatter
+ SimpleDateFormat *sdf = new SimpleDateFormat(pattern,override,Locale::getChina(),status);
+ failure(status, "new SimpleDateFormat with override", TRUE);
+
+ UDate thedate = date(2009-1900, UCAL_JULY, 28);
+ FieldPosition pos(0);
+ UnicodeString result;
+ sdf->format(thedate,result,pos);
+
+ UnicodeString expected = "\\u4e8c\\u3007\\u3007\\u4e5d\\u5e74\\u4e03\\u6708\\u4e8c\\u5341\\u516b\\u65e5";
+ expected = expected.unescape();
+ if (result != expected) {
+ dataerrln((UnicodeString)"FAIL: -> " + result + " expected -> " + expected);
+ }
+
+ UDate parsedate = sdf->parse(expected,status);
+ if ( parsedate != thedate ) {
+ UnicodeString pat1 ("yyyy-MM-dd'T'HH:mm:ss'Z'", -1, US_INV );
+ SimpleDateFormat *usf = new SimpleDateFormat(pat1,Locale::getEnglish(),status);
+ UnicodeString parsedres,expres;
+ usf->format(parsedate,parsedres,pos);
+ usf->format(thedate,expres,pos);
+ dataerrln((UnicodeString)"FAIL: parsed -> " + parsedres + " expected -> " + expres);
+ delete usf;
+ }
+ delete sdf;
+}
+
+// Test case for #8675
+// Incorrect parse offset with stand alone GMT string on 2nd or later iteration.
+void DateFormatTest::TestStandAloneGMTParse() {
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat *sdf = new SimpleDateFormat("ZZZZ", Locale(""), status);
+
+ if (U_SUCCESS(status)) {
+
+ UnicodeString inText("GMT$$$");
+ for (int32_t i = 0; i < 10; i++) {
+ ParsePosition pos(0);
+ sdf->parse(inText, pos);
+ if (pos.getIndex() != 3) {
+ errln((UnicodeString)"FAIL: Incorrect output parse position: actual=" + pos.getIndex() + " expected=3");
+ }
+ }
+
+ delete sdf;
+ } else {
+ dataerrln("Unable to create SimpleDateFormat - %s", u_errorName(status));
+ }
+}
+
+void DateFormatTest::TestParsePosition() {
+ const char* TestData[][4] = {
+ // {<pattern>, <lead>, <date string>, <trail>}
+ {"yyyy-MM-dd HH:mm:ssZ", "", "2010-01-10 12:30:00+0500", ""},
+ {"yyyy-MM-dd HH:mm:ss ZZZZ", "", "2010-01-10 12:30:00 GMT+05:00", ""},
+ {"Z HH:mm:ss", "", "-0100 13:20:30", ""},
+ {"y-M-d Z", "", "2011-8-25 -0400", " Foo"},
+ {"y/M/d H:mm:ss z", "", "2011/7/1 12:34:00 PDT", ""},
+ {"y/M/d H:mm:ss z", "+123", "2011/7/1 12:34:00 PDT", " PST"},
+ {"vvvv a h:mm:ss", "", "Pacific Time AM 10:21:45", ""},
+ {"HH:mm v M/d", "111", "14:15 PT 8/10", " 12345"},
+ {"'time zone:' VVVV 'date:' yyyy-MM-dd", "xxxx", "time zone: Los Angeles Time date: 2010-02-25", "xxxx"},
+ {"yG", "", "2012AD", ""},
+ {"yG", "", "2012", "x"},
+ {0, 0, 0, 0},
+ };
+
+ for (int32_t i = 0; TestData[i][0]; i++) {
+ UErrorCode status = U_ZERO_ERROR;
+ SimpleDateFormat *sdf = new SimpleDateFormat(UnicodeString(TestData[i][0]), status);
+ if (failure(status, "new SimpleDateFormat", TRUE)) return;
+
+ int32_t startPos, resPos;
+
+ // lead text
+ UnicodeString input(TestData[i][1]);
+ startPos = input.length();
+
+ // date string
+ input += TestData[i][2];
+ resPos = input.length();
+
+ // trail text
+ input += TestData[i][3];
+
+ ParsePosition pos(startPos);
+ //UDate d = sdf->parse(input, pos);
+ (void)sdf->parse(input, pos);
+
+ if (pos.getIndex() != resPos) {
+ errln(UnicodeString("FAIL: Parsing [") + input + "] with pattern [" + TestData[i][0] + "] returns position - "
+ + pos.getIndex() + ", expected - " + resPos);
+ }
+
+ delete sdf;
+ }
+}
+
+
+typedef struct {
+ int32_t era;
+ int32_t year;
+ int32_t month; // 1-based
+ int32_t isLeapMonth;
+ int32_t day;
+} ChineseCalTestDate;
+
+#define NUM_TEST_DATES 3
+
+typedef struct {
+ const char * locale;
+ int32_t style; // <0 => custom
+ UnicodeString dateString[NUM_TEST_DATES];
+} MonthPatternItem;
+
+void DateFormatTest::TestMonthPatterns()
+{
+ const ChineseCalTestDate dates[NUM_TEST_DATES] = {
+ // era yr mo lp da
+ { 78, 29, 4, 0, 2 }, // (in chinese era 78) gregorian 2012-4-22
+ { 78, 29, 4, 1, 2 }, // (in chinese era 78) gregorian 2012-5-22
+ { 78, 29, 5, 0, 2 }, // (in chinese era 78) gregorian 2012-6-20
+ };
+
+ const MonthPatternItem items[] = {
+ // locale date style; expected formats for the 3 dates above
+ { "root@calendar=chinese", DateFormat::kLong, { UnicodeString("ren-chen Month4 2"), UnicodeString("ren-chen Month4bis 2"), UnicodeString("ren-chen Month5 2") } },
+ { "root@calendar=chinese", DateFormat::kShort, { UnicodeString("29-04-02"), UnicodeString("29-04bis-02"), UnicodeString("29-05-02") } },
+ { "root@calendar=chinese", -1, { UnicodeString("29-4-2"), UnicodeString("29-4bis-2"), UnicodeString("29-5-2") } },
+ { "root@calendar=chinese", -2, { UnicodeString("78x29-4-2"), UnicodeString("78x29-4bis-2"), UnicodeString("78x29-5-2") } },
+ { "root@calendar=chinese", -3, { UnicodeString("ren-chen-4-2"), UnicodeString("ren-chen-4bis-2"), UnicodeString("ren-chen-5-2") } },
+ { "root@calendar=chinese", -4, { UnicodeString("ren-chen Month4 2"), UnicodeString("ren-chen Month4bis 2"), UnicodeString("ren-chen Month5 2") } },
+ { "en@calendar=gregorian", -3, { UnicodeString("2012-4-22"), UnicodeString("2012-5-22"), UnicodeString("2012-6-20") } },
+ { "en@calendar=chinese", DateFormat::kLong, { UnicodeString("Month4 2, ren-chen"), UnicodeString("Month4bis 2, ren-chen"), UnicodeString("Month5 2, ren-chen") } },
+ { "en@calendar=chinese", DateFormat::kShort, { UnicodeString("4/2/29"), UnicodeString("4bis/2/29"), UnicodeString("5/2/29") } },
+ { "zh@calendar=chinese", DateFormat::kLong, { CharsToUnicodeString("\\u58EC\\u8FB0\\u5E74\\u56DB\\u6708\\u4E8C\\u65E5"),
+ CharsToUnicodeString("\\u58EC\\u8FB0\\u5E74\\u95F0\\u56DB\\u6708\\u4E8C\\u65E5"),
+ CharsToUnicodeString("\\u58EC\\u8FB0\\u5E74\\u4E94\\u6708\\u4E8C\\u65E5") } },
+ { "zh@calendar=chinese", DateFormat::kShort, { CharsToUnicodeString("\\u58EC\\u8FB0-4-2"),
+ CharsToUnicodeString("\\u58EC\\u8FB0-\\u95F04-2"),
+ CharsToUnicodeString("\\u58EC\\u8FB0-5-2") } },
+ { "zh@calendar=chinese", -3, { CharsToUnicodeString("\\u58EC\\u8FB0-4-2"),
+ CharsToUnicodeString("\\u58EC\\u8FB0-\\u95F04-2"),
+ CharsToUnicodeString("\\u58EC\\u8FB0-5-2") } },
+ { "zh@calendar=chinese", -4, { CharsToUnicodeString("\\u58EC\\u8FB0 \\u56DB\\u6708 2"),
+ CharsToUnicodeString("\\u58EC\\u8FB0 \\u95F0\\u56DB\\u6708 2"),
+ CharsToUnicodeString("\\u58EC\\u8FB0 \\u4E94\\u6708 2") } },
+ { "zh_Hant@calendar=chinese", DateFormat::kLong, { CharsToUnicodeString("\\u58EC\\u8FB0\\u5E74\\u56DB\\u6708\\u4E8C\\u65E5"),
+ CharsToUnicodeString("\\u58EC\\u8FB0\\u5E74\\u958F\\u56DB\\u6708\\u4E8C\\u65E5"),
+ CharsToUnicodeString("\\u58EC\\u8FB0\\u5E74\\u4E94\\u6708\\u4E8C\\u65E5") } },
+ { "zh_Hant@calendar=chinese", DateFormat::kShort, { CharsToUnicodeString("\\u58EC\\u8FB0/4/2"),
+ CharsToUnicodeString("\\u58EC\\u8FB0/\\u958F4/2"),
+ CharsToUnicodeString("\\u58EC\\u8FB0/5/2") } },
+ { "fr@calendar=chinese", DateFormat::kLong, { CharsToUnicodeString("2 s\\u00ECyu\\u00E8 ren-chen"),
+ CharsToUnicodeString("2 s\\u00ECyu\\u00E8bis ren-chen"),
+ CharsToUnicodeString("2 w\\u01D4yu\\u00E8 ren-chen") } },
+ { "fr@calendar=chinese", DateFormat::kShort, { UnicodeString("2/4/29"), UnicodeString("2/4bis/29"), UnicodeString("2/5/29") } },
+ { "en@calendar=dangi", DateFormat::kLong, { UnicodeString("Month3bis 2, 29"), UnicodeString("Month4 2, 29"), UnicodeString("Month5 1, 29") } },
+ { "en@calendar=dangi", DateFormat::kShort, { UnicodeString("3bis/2/29"), UnicodeString("4/2/29"), UnicodeString("5/1/29") } },
+ { "ko@calendar=dangi", DateFormat::kLong, { CharsToUnicodeString("\\uC784\\uC9C4\\uB144 3bis\\uC6D4 2\\uC77C"),
+ CharsToUnicodeString("\\uC784\\uC9C4\\uB144 4\\uC6D4 2\\uC77C"),
+ CharsToUnicodeString("\\uC784\\uC9C4\\uB144 5\\uC6D4 1\\uC77C") } },
+ { "ko@calendar=dangi", DateFormat::kShort, { CharsToUnicodeString("29. 3bis. 2."),
+ CharsToUnicodeString("29. 4. 2."),
+ CharsToUnicodeString("29. 5. 1.") } },
+ // terminator
+ { NULL, 0, { UnicodeString(""), UnicodeString(""), UnicodeString("") } }
+ };
+
+ //. style: -1 -2 -3 -4
+ const UnicodeString customPatterns[] = { "y-Ml-d", "G'x'y-Ml-d", "U-M-d", "U MMM d" }; // like old root pattern, using 'l'
+
+ UErrorCode status = U_ZERO_ERROR;
+ Locale rootChineseCalLocale = Locale::createFromName("root@calendar=chinese");
+ Calendar * rootChineseCalendar = Calendar::createInstance(rootChineseCalLocale, status);
+ if (U_SUCCESS(status)) {
+ const MonthPatternItem * itemPtr;
+ for (itemPtr = items; itemPtr->locale != NULL; itemPtr++ ) {
+ Locale locale = Locale::createFromName(itemPtr->locale);
+ DateFormat * dmft = (itemPtr->style >= 0)?
+ DateFormat::createDateInstance((DateFormat::EStyle)itemPtr->style, locale):
+ new SimpleDateFormat(customPatterns[-itemPtr->style - 1], locale, status);
+ if ( dmft != NULL ) {
+ if (U_SUCCESS(status)) {
+ const ChineseCalTestDate * datePtr = dates;
+ int32_t idate;
+ for (idate = 0; idate < NUM_TEST_DATES; idate++, datePtr++) {
+ rootChineseCalendar->clear();
+ rootChineseCalendar->set(UCAL_ERA, datePtr->era);
+ rootChineseCalendar->set(datePtr->year, datePtr->month-1, datePtr->day);
+ rootChineseCalendar->set(UCAL_IS_LEAP_MONTH, datePtr->isLeapMonth);
+ UnicodeString result;
+ FieldPosition fpos(0);
+ dmft->format(*rootChineseCalendar, result, fpos);
+ if ( result.compare(itemPtr->dateString[idate]) != 0 ) {
+ errln( UnicodeString("FAIL: Chinese calendar format for locale ") + UnicodeString(itemPtr->locale) + ", style " + itemPtr->style +
+ ", expected \"" + itemPtr->dateString[idate] + "\", got \"" + result + "\"");
+ } else {
+ // formatted OK, try parse
+ ParsePosition ppos(0);
+ // ensure we are really parsing the fields we should be
+ rootChineseCalendar->set(UCAL_YEAR, 1);
+ rootChineseCalendar->set(UCAL_MONTH, 0);
+ rootChineseCalendar->set(UCAL_IS_LEAP_MONTH, 0);
+ rootChineseCalendar->set(UCAL_DATE, 1);
+ //
+ dmft->parse(result, *rootChineseCalendar, ppos);
+ int32_t year = rootChineseCalendar->get(UCAL_YEAR, status);
+ int32_t month = rootChineseCalendar->get(UCAL_MONTH, status) + 1;
+ int32_t isLeapMonth = rootChineseCalendar->get(UCAL_IS_LEAP_MONTH, status);
+ int32_t day = rootChineseCalendar->get(UCAL_DATE, status);
+ if ( ppos.getIndex() < result.length() || year != datePtr->year || month != datePtr->month || isLeapMonth != datePtr->isLeapMonth || day != datePtr->day ) {
+ errln( UnicodeString("FAIL: Chinese calendar parse for locale ") + UnicodeString(itemPtr->locale) + ", style " + itemPtr->style +
+ ", string \"" + result + "\", expected " + datePtr->year +"-"+datePtr->month+"("+datePtr->isLeapMonth+")-"+datePtr->day + ", got pos " +
+ ppos.getIndex() + " " + year +"-"+month+"("+isLeapMonth+")-"+day);
+ }
+ }
+ }
+ } else {
+ dataerrln("Error creating SimpleDateFormat for Chinese calendar- %s", u_errorName(status));
+ }
+ delete dmft;
+ } else {
+ dataerrln("FAIL: Unable to create DateFormat for Chinese calendar- %s", u_errorName(status));
+ }
+ }
+ delete rootChineseCalendar;
+ } else {
+ errln(UnicodeString("FAIL: Unable to create Calendar for root@calendar=chinese"));
+ }
+}
+
+typedef struct {
+ const char * locale;
+ UnicodeString pattern;
+ UDisplayContext capitalizationContext;
+ UnicodeString expectedFormat;
+} TestContextItem;
+
+void DateFormatTest::TestContext()
+{
+ const UDate july022008 = 1215000001979.0;
+ const TestContextItem items[] = {
+ //locale pattern capitalizationContext expected formatted date
+ { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_NONE, UnicodeString("juillet 2008") },
+#if !UCONFIG_NO_BREAK_ITERATION
+ { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, UnicodeString("juillet 2008") },
+ { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, UnicodeString("Juillet 2008") },
+ { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, UnicodeString("juillet 2008") },
+ { "fr", UnicodeString("MMMM y"), UDISPCTX_CAPITALIZATION_FOR_STANDALONE, UnicodeString("Juillet 2008") },
+#endif
+ { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_NONE, CharsToUnicodeString("\\u010Dervenec 2008") },
+#if !UCONFIG_NO_BREAK_ITERATION
+ { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, CharsToUnicodeString("\\u010Dervenec 2008") },
+ { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, CharsToUnicodeString("\\u010Cervenec 2008") },
+ { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, CharsToUnicodeString("\\u010Cervenec 2008") },
+ { "cs", UnicodeString("LLLL y"), UDISPCTX_CAPITALIZATION_FOR_STANDALONE, CharsToUnicodeString("\\u010Dervenec 2008") },
+#endif
+ // terminator
+ { NULL, UnicodeString(""), (UDisplayContext)0, UnicodeString("") }
+ };
+ UErrorCode status = U_ZERO_ERROR;
+ Calendar* cal = Calendar::createInstance(status);
+ if (U_FAILURE(status)) {
+ dataerrln(UnicodeString("FAIL: Unable to create Calendar for default timezone and locale."));
+ } else {
+ cal->setTime(july022008, status);
+ const TestContextItem * itemPtr;
+ for (itemPtr = items; itemPtr->locale != NULL; itemPtr++ ) {
+ Locale locale = Locale::createFromName(itemPtr->locale);
+ status = U_ZERO_ERROR;
+ SimpleDateFormat * sdmft = new SimpleDateFormat(itemPtr->pattern, locale, status);
+ if (U_FAILURE(status)) {
+ dataerrln(UnicodeString("FAIL: Unable to create SimpleDateFormat for specified pattern with locale ") + UnicodeString(itemPtr->locale));
+ } else {
+ sdmft->setContext(itemPtr->capitalizationContext, status);
+ UnicodeString result;
+ FieldPosition pos(0);
+ sdmft->format(*cal, result, pos);
+ if (result.compare(itemPtr->expectedFormat) != 0) {
+ errln(UnicodeString("FAIL: format for locale ") + UnicodeString(itemPtr->locale) +
+ ", status " + (int)status +
+ ", capitalizationContext " + (int)itemPtr->capitalizationContext +
+ ", expected " + itemPtr->expectedFormat + ", got " + result);
+ }
+ }
+ if (sdmft) {
+ delete sdmft;
+ }
+ }
+ }
+ if (cal) {
+ delete cal;
+ }
+}
+
+// test item for a particular locale + calendar and date format
+typedef struct {
+ int32_t year;
+ int32_t month;
+ int32_t day;
+ int32_t hour;
+ int32_t minute;
+ UnicodeString formattedDate;
+} CalAndFmtTestItem;
+
+// test item giving locale + calendar, date format, and CalAndFmtTestItems
+typedef struct {
+ const char * locale; // with calendar
+ DateFormat::EStyle style;
+ const CalAndFmtTestItem *caftItems;
+} TestNonGregoItem;
+
+void DateFormatTest::TestNonGregoFmtParse()
+{
+ // test items for he@calendar=hebrew, long date format
+ const CalAndFmtTestItem cafti_he_hebrew_long[] = {
+ { 4999, 12, 29, 12, 0, CharsToUnicodeString("\\u05DB\\u05F4\\u05D8 \\u05D1\\u05D0\\u05DC\\u05D5\\u05DC \\u05D3\\u05F3\\u05EA\\u05EA\\u05E7\\u05E6\\u05F4\\u05D8") },
+ { 5100, 0, 1, 12, 0, CharsToUnicodeString("\\u05D0\\u05F3 \\u05D1\\u05EA\\u05E9\\u05E8\\u05D9 \\u05E7\\u05F3") },
+ { 5774, 5, 1, 12, 0, CharsToUnicodeString("\\u05D0\\u05F3 \\u05D1\\u05D0\\u05D3\\u05E8 \\u05D0\\u05F3 \\u05EA\\u05E9\\u05E2\\u05F4\\u05D3") },
+ { 5999, 12, 29, 12, 0, CharsToUnicodeString("\\u05DB\\u05F4\\u05D8 \\u05D1\\u05D0\\u05DC\\u05D5\\u05DC \\u05EA\\u05EA\\u05E7\\u05E6\\u05F4\\u05D8") },
+ { 6100, 0, 1, 12, 0, CharsToUnicodeString("\\u05D0\\u05F3 \\u05D1\\u05EA\\u05E9\\u05E8\\u05D9 \\u05D5\\u05F3\\u05E7\\u05F3") },
+ { 0, 0, 0, 0, 0, UnicodeString("") } // terminator
+ };
+ // overal test items
+ const TestNonGregoItem items[] = {
+ { "he@calendar=hebrew", DateFormat::kLong, cafti_he_hebrew_long },
+ { NULL, DateFormat::kNone, NULL } // terminator
+ };
+ const TestNonGregoItem * itemPtr;
+ for (itemPtr = items; itemPtr->locale != NULL; itemPtr++) {
+ Locale locale = Locale::createFromName(itemPtr->locale);
+ DateFormat * dfmt = DateFormat::createDateInstance(itemPtr->style, locale);
+ if (dfmt == NULL) {
+ dataerrln("DateFormat::createDateInstance fails for locale %s", itemPtr->locale);
+ } else {
+ Calendar * cal = (dfmt->getCalendar())->clone();
+ if (cal == NULL) {
+ dataerrln("(DateFormat::getCalendar)->clone() fails for locale %s", itemPtr->locale);
+ } else {
+ const CalAndFmtTestItem * caftItemPtr;
+ for (caftItemPtr = itemPtr->caftItems; caftItemPtr->year != 0; caftItemPtr++) {
+ cal->clear();
+ cal->set(UCAL_YEAR, caftItemPtr->year);
+ cal->set(UCAL_MONTH, caftItemPtr->month);
+ cal->set(UCAL_DATE, caftItemPtr->day);
+ cal->set(UCAL_HOUR_OF_DAY, caftItemPtr->hour);
+ cal->set(UCAL_MINUTE, caftItemPtr->minute);
+ UnicodeString result;
+ FieldPosition fpos(0);
+ dfmt->format(*cal, result, fpos);
+ if ( result.compare(caftItemPtr->formattedDate) != 0 ) {
+ errln( UnicodeString("FAIL: date format for locale ") + UnicodeString(itemPtr->locale) + ", style " + itemPtr->style +
+ ", expected \"" + caftItemPtr->formattedDate + "\", got \"" + result + "\"");
+ } else {
+ // formatted OK, try parse
+ ParsePosition ppos(0);
+ dfmt->parse(result, *cal, ppos);
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t year = cal->get(UCAL_YEAR, status);
+ int32_t month = cal->get(UCAL_MONTH, status);
+ int32_t day = cal->get(UCAL_DATE, status);
+ if ( U_FAILURE(status) || ppos.getIndex() < result.length() || year != caftItemPtr->year || month != caftItemPtr->month || day != caftItemPtr->day ) {
+ errln( UnicodeString("FAIL: date parse for locale ") + UnicodeString(itemPtr->locale) + ", style " + itemPtr->style +
+ ", string \"" + result + "\", expected " + caftItemPtr->year +"-"+caftItemPtr->month+"-"+caftItemPtr->day + ", got pos " +
+ ppos.getIndex() + " " + year +"-"+month+"-"+day + " status " + UnicodeString(u_errorName(status)) );
+ }
+ }
+ }
+ delete cal;
+ }
+ delete dfmt;
+ }
+ }
+}
+
+static const UDate TEST_DATE = 1326585600000.; // 2012-jan-15
+
+void DateFormatTest::TestDotAndAtLeniency() {
+ // Test for date/time parsing regression with CLDR 22.1/ICU 50 pattern strings.
+ // For details see http://bugs.icu-project.org/trac/ticket/9789
+ static const char *locales[] = { "en", "fr" };
+ for (int32_t i = 0; i < LENGTHOF(locales); ++i) {
+ Locale locale(locales[i]);
+
+ for (DateFormat::EStyle dateStyle = DateFormat::FULL; dateStyle <= DateFormat::SHORT;
+ dateStyle = static_cast<DateFormat::EStyle>(dateStyle + 1)) {
+ LocalPointer<DateFormat> dateFormat(DateFormat::createDateInstance(dateStyle, locale));
+
+ for (DateFormat::EStyle timeStyle = DateFormat::FULL; timeStyle <= DateFormat::SHORT;
+ timeStyle = static_cast<DateFormat::EStyle>(timeStyle + 1)) {
+ LocalPointer<DateFormat> format(DateFormat::createDateTimeInstance(dateStyle, timeStyle, locale));
+ LocalPointer<DateFormat> timeFormat(DateFormat::createTimeInstance(timeStyle, locale));
+ UnicodeString formattedString;
+ if (format.isNull()) {
+ dataerrln("Unable to create DateFormat");
+ continue;
+ }
+ format->format(TEST_DATE, formattedString);
+
+ if (!showParse(*format, formattedString)) {
+ errln(UnicodeString(" with date-time: dateStyle=") + dateStyle + " timeStyle=" + timeStyle);
+ }
+
+ UnicodeString ds, ts;
+ formattedString = dateFormat->format(TEST_DATE, ds) + " " + timeFormat->format(TEST_DATE, ts);
+ if (!showParse(*format, formattedString)) {
+ errln(UnicodeString(" with date sp sp time: dateStyle=") + dateStyle + " timeStyle=" + timeStyle);
+ }
+ if (formattedString.indexOf("n ") >= 0) { // will add "." after the end of text ending in 'n', like Jan.
+ UnicodeString plusDot(formattedString);
+ plusDot.findAndReplace("n ", "n. ").append(".");
+ if (!showParse(*format, plusDot)) {
+ errln(UnicodeString(" with date plus-dot time: dateStyle=") + dateStyle + " timeStyle=" + timeStyle);
+ }
+ }
+ if (formattedString.indexOf(". ") >= 0) { // will subtract "." at the end of strings.
+ UnicodeString minusDot(formattedString);
+ minusDot.findAndReplace(". ", " ");
+ if (!showParse(*format, minusDot)) {
+ errln(UnicodeString(" with date minus-dot time: dateStyle=") + dateStyle + " timeStyle=" + timeStyle);
+ }
+ }
+ }
+ }
+ }
+}
+
+UBool DateFormatTest::showParse(DateFormat &format, const UnicodeString &formattedString) {
+ ParsePosition parsePosition;
+ UDate parsed = format.parse(formattedString, parsePosition);
+ UBool ok = TEST_DATE == parsed && parsePosition.getIndex() == formattedString.length();
+ UnicodeString pattern;
+ static_cast<SimpleDateFormat &>(format).toPattern(pattern);
+ if (ok) {
+ logln(pattern + " parsed: " + formattedString);
+ } else {
+ errln(pattern + " fails to parse: " + formattedString);
+ }
+ return ok;
+}