X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/d25163bfc042dbef00577180ee21dd3460fc3715..2ca993e82fb37b597a3c73ecd1586a139a6579c5:/icuSources/test/intltest/dtfmttst.cpp diff --git a/icuSources/test/intltest/dtfmttst.cpp b/icuSources/test/intltest/dtfmttst.cpp index e4fa37b6..d3e697bf 100644 --- a/icuSources/test/intltest/dtfmttst.cpp +++ b/icuSources/test/intltest/dtfmttst.cpp @@ -1,6 +1,6 @@ /******************************************************************** * COPYRIGHT: - * Copyright (c) 1997-2015, International Business Machines + * Copyright (c) 1997-2016, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************/ @@ -27,8 +27,6 @@ #include "windttst.h" #endif -#define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) - #define ASSERT_OK(status) if(U_FAILURE(status)) {errcheckln(status, #status " = %s @ %s:%d", u_errorName(status), __FILE__, __LINE__); return; } // ***************************************************************************** @@ -96,6 +94,7 @@ void DateFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &nam TESTCASE_AUTO(TestMonthPatterns); TESTCASE_AUTO(TestContext); TESTCASE_AUTO(TestNonGregoFmtParse); + TESTCASE_AUTO(TestFormatsWithNumberSystems); /* TESTCASE_AUTO(TestRelativeError); TESTCASE_AUTO(TestRelativeOther); @@ -113,6 +112,14 @@ void DateFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &nam TESTCASE_AUTO(TestDFSCreateForLocaleWithCalendarInLocale); TESTCASE_AUTO(TestChangeCalendar); + TESTCASE_AUTO(TestPatternFromSkeleton); + + TESTCASE_AUTO(TestAmPmMidnightNoon); + TESTCASE_AUTO(TestFlexibleDayPeriod); + TESTCASE_AUTO(TestDayPeriodWithLocales); + TESTCASE_AUTO(TestMinuteSecondFieldsInOddPlaces); + TESTCASE_AUTO(TestDayPeriodParsing); + TESTCASE_AUTO_END; } @@ -127,21 +134,21 @@ void DateFormatTest::TestPatterns() { {UDAT_QUARTER, "QQQQ", "en", "QQQQ"}, {UDAT_ABBR_QUARTER, "QQQ", "en", "QQQ"}, - {UDAT_YEAR_QUARTER, "yQQQQ", "en", "QQQQ y"}, + {UDAT_YEAR_QUARTER, "yQQQQ", "en", "QQQQ y"}, {UDAT_YEAR_ABBR_QUARTER, "yQQQ", "en", "QQQ y"}, {UDAT_NUM_MONTH, "M", "en", "L"}, {UDAT_ABBR_MONTH, "MMM", "en", "LLL"}, {UDAT_MONTH, "MMMM", "en", "LLLL"}, - {UDAT_YEAR_NUM_MONTH, "yM","en","M/y"}, + {UDAT_YEAR_NUM_MONTH, "yM","en","M/y"}, {UDAT_YEAR_ABBR_MONTH, "yMMM","en","MMM y"}, {UDAT_YEAR_MONTH, "yMMMM","en","MMMM y"}, {UDAT_DAY, "d","en","d"}, - {UDAT_YEAR_NUM_MONTH_DAY, "yMd", "en", "M/d/y"}, + {UDAT_YEAR_NUM_MONTH_DAY, "yMd", "en", "M/d/y"}, {UDAT_YEAR_ABBR_MONTH_DAY, "yMMMd", "en", "MMM d, y"}, {UDAT_YEAR_MONTH_DAY, "yMMMMd", "en", "MMMM d, y"}, - {UDAT_YEAR_NUM_MONTH_WEEKDAY_DAY, "yMEd", "en", "EEE, M/d/y"}, + {UDAT_YEAR_NUM_MONTH_WEEKDAY_DAY, "yMEd", "en", "EEE, M/d/y"}, {UDAT_YEAR_ABBR_MONTH_WEEKDAY_DAY, "yMMMEd", "en", "EEE, MMM d, y"}, {UDAT_YEAR_MONTH_WEEKDAY_DAY, "yMMMMEEEEd", "en", "EEEE, MMMM d, y"}, @@ -182,15 +189,15 @@ void DateFormatTest::TestPatterns() { UnicodeString expectedPattern(EXPECTED[i].expectedPattern, -1, US_INV); Locale locale(EXPECTED[i].localeID); if (actualPattern != expectedPattern) { - errln("FAILURE! Expected pattern: " + expectedPattern + + errln("FAILURE! Expected pattern: " + expectedPattern + " but was: " + actualPattern); } - // Verify that DataFormat instances produced contain the correct + // Verify that DataFormat instances produced contain the correct // localized patterns // TODO: use DateFormat::getInstanceForSkeleton(), ticket #9029 // Java test code: - // DateFormat date1 = DateFormat.getPatternInstance(actualPattern, + // DateFormat date1 = DateFormat.getPatternInstance(actualPattern, // locale); // DateFormat date2 = DateFormat.getPatternInstance(Calendar.getInstance(locale), // actualPattern, locale); @@ -215,11 +222,11 @@ void DateFormatTest::TestPatterns() { date1.toLocalizedPattern(actualLocalPattern1, errorCode); date2.toLocalizedPattern(actualLocalPattern2, errorCode); if (actualLocalPattern1 != expectedLocalPattern) { - errln("FAILURE! Expected local pattern: " + expectedLocalPattern + errln("FAILURE! Expected local pattern: " + expectedLocalPattern + " but was: " + actualLocalPattern1); } if (actualLocalPattern2 != expectedLocalPattern) { - errln("FAILURE! Expected local pattern: " + expectedLocalPattern + errln("FAILURE! Expected local pattern: " + expectedLocalPattern + " but was: " + actualLocalPattern2); } } @@ -433,7 +440,11 @@ DateFormatTest::escape(UnicodeString& s) /** * This MUST be kept in sync with DateFormatSymbols.gPatternChars. */ -static const char* PATTERN_CHARS = "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxr:"; +#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR +static const char* PATTERN_CHARS = "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB:"; +#else +static const char* PATTERN_CHARS = "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB"; +#endif /** * A list of the names of all the fields in DateFormat. @@ -475,11 +486,13 @@ static const char* DATEFORMAT_FIELD_NAMES[] = { "TIMEZONE_ISO_FIELD", "TIMEZONE_ISO_LOCAL_FIELD", "RELATED_YEAR_FIELD", + "AM_PM_MIDNIGHT_NOON_FIELD", + "FLEXIBLE_DAY_PERIOD_FIELD", "UDAT_TIME_SEPARATOR_FIELD", }; static const int32_t DATEFORMAT_FIELD_NAMES_LENGTH = - sizeof(DATEFORMAT_FIELD_NAMES) / sizeof(DATEFORMAT_FIELD_NAMES[0]); + UPRV_LENGTHOF(DATEFORMAT_FIELD_NAMES); /** * Verify that returned field position indices are correct. @@ -501,7 +514,11 @@ void DateFormatTest::TestFieldPosition() { assertEquals("patternChars", PATTERN_CHARS, rootSyms.getLocalPatternChars(buf)); assertEquals("patternChars", PATTERN_CHARS, DateFormatSymbols::getPatternUChars()); assertTrue("DATEFORMAT_FIELD_NAMES", DATEFORMAT_FIELD_NAMES_LENGTH == UDAT_FIELD_COUNT); +#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR assertTrue("Data", UDAT_FIELD_COUNT == uprv_strlen(PATTERN_CHARS)); +#else + assertTrue("Data", UDAT_FIELD_COUNT == uprv_strlen(PATTERN_CHARS) + 1); // +1 for missing TIME_SEPARATOR pattern char +#endif // Create test formatters const int32_t COUNT = 4; @@ -530,26 +547,44 @@ void DateFormatTest::TestFieldPosition() { const char* EXPECTED[] = { "", "1997", "August", "13", "", "", "34", "12", "", "Wednesday", "", "", "", "", "PM", "2", "", "Pacific Daylight Time", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", ":", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", +#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR + ":", +#else + "", +#endif "", "1997", "ao\\u00FBt", "13", "", "14", "34", "12", "", "mercredi", "", "", "", "", "", "", "", "heure d\\u2019\\u00E9t\\u00E9 du Pacifique", "", "", - "", "", "", "", "", "", "", "", "", "", - "", "", "", "", "", ":", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", +#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR + ":", +#else + "", +#endif "AD", "1997", "8", "13", "14", "14", "34", "12", "5", "Wed", "225", "2", "33", "3", "PM", "2", "2", "PDT", "1997", "4", "1997", "2450674", "52452513", "-0700", "PT", "4", "8", "3", "3", "uslax", - "1997", "GMT-7", "-07", "-07", "1997", ":", + "1997", "GMT-7", "-07", "-07", "1997", "PM", "in the afternoon", +#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR + ":", +#else + "", +#endif "Anno Domini", "1997", "August", "0013", "0014", "0014", "0034", "0012", "5130", "Wednesday", "0225", "0002", "0033", "0003", "PM", "0002", "0002", "Pacific Daylight Time", "1997", "Wednesday", "1997", "2450674", "52452513", "GMT-07:00", "Pacific Time", "Wednesday", "August", "3rd quarter", "3rd quarter", "Los Angeles Time", - "1997", "GMT-07:00", "-0700", "-0700", "1997", ":", + "1997", "GMT-07:00", "-0700", "-0700", "1997", "PM", "in the afternoon", +#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR + ":", +#else + "", +#endif }; - const int32_t EXPECTED_LENGTH = sizeof(EXPECTED)/sizeof(EXPECTED[0]); + const int32_t EXPECTED_LENGTH = UPRV_LENGTHOF(EXPECTED); assertTrue("data size", EXPECTED_LENGTH == COUNT * UDAT_FIELD_COUNT); @@ -625,7 +660,7 @@ void DateFormatTest::TestGeneral() { "y/M/d H:mm:ss.SSS", "F", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.567", "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", }; - expect(DATA, ARRAY_SIZE(DATA), Locale("en", "", "")); + expect(DATA, UPRV_LENGTHOF(DATA), Locale("en", "", "")); } // ------------------------------------- @@ -942,11 +977,11 @@ DateFormatTest::TestBadInput135() DateFormat::EStyle looks[] = { DateFormat::SHORT, DateFormat::MEDIUM, DateFormat::LONG, DateFormat::FULL }; - int32_t looks_length = (int32_t)(sizeof(looks) / sizeof(looks[0])); + int32_t looks_length = UPRV_LENGTHOF(looks); const char* strings[] = { "Mar 15", "Mar 15 1997", "asdf", "3/1/97 1:23:", "3/1/00 1:23:45 AM" }; - int32_t strings_length = (int32_t)(sizeof(strings) / sizeof(strings[0])); + int32_t strings_length = UPRV_LENGTHOF(strings); DateFormat *full = DateFormat::createDateTimeInstance(DateFormat::LONG, DateFormat::LONG); if(full==NULL) { dataerrln("could not create date time instance"); @@ -1044,7 +1079,7 @@ static const char* const inputStrings[] = { "3:00 pm Jan 1, 1997", 0, 0, 0, 0, 0, 0, 0, "0003", "3:00 PM January 1, 1997", }; #endif - + // ------------------------------------- /** @@ -1064,8 +1099,8 @@ DateFormatTest::TestBadInput135a() } const char* s; UDate date; - const uint32_t PF_LENGTH = (int32_t)(sizeof(parseFormats)/sizeof(parseFormats[0])); - const uint32_t INPUT_LENGTH = (int32_t)(sizeof(inputStrings)/sizeof(inputStrings[0])); + const uint32_t PF_LENGTH = UPRV_LENGTHOF(parseFormats); + const uint32_t INPUT_LENGTH = UPRV_LENGTHOF(inputStrings); dateParse->applyPattern("d MMMM, yyyy"); dateParse->adoptTimeZone(TimeZone::createDefault()); @@ -1249,7 +1284,7 @@ DateFormatTest::TestDateFormatZone146() UnicodeString("short format: "), UnicodeString("4/4/97 11:00 PM"), UnicodeString("M/d/yy h:mm a") }; - int32_t DATA_length = (int32_t)(sizeof(DATA) / sizeof(DATA[0])); + int32_t DATA_length = UPRV_LENGTHOF(DATA); for (int32_t i=0; iparse(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; + 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 + + // create formatter SimpleDateFormat *sdf = new SimpleDateFormat(pattern,override,Locale::getChina(),status); if (failure(status, "new SimpleDateFormat with override", TRUE)) { return; @@ -3902,13 +3942,13 @@ void DateFormatTest::TestFormalChineseDate() { FieldPosition pos(0); UnicodeString result; sdf->format(thedate,result,pos); - - UnicodeString expected = "\\u4e8c\\u3007\\u3007\\u4e5d\\u5e74\\u4e03\\u6708\\u4e8c\\u5341\\u516b\\u65e5"; + + 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); - } - + 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 ); @@ -3916,7 +3956,7 @@ void DateFormatTest::TestFormalChineseDate() { UnicodeString parsedres,expres; usf->format(parsedate,parsedres,pos); usf->format(thedate,expres,pos); - dataerrln((UnicodeString)"FAIL: parsed -> " + parsedres + " expected -> " + expres); + dataerrln((UnicodeString)"FAIL: parsed -> " + parsedres + " expected -> " + expres); delete usf; } delete sdf; @@ -3927,7 +3967,7 @@ void DateFormatTest::TestFormalChineseDate() { void DateFormatTest::TestStandAloneGMTParse() { UErrorCode status = U_ZERO_ERROR; SimpleDateFormat *sdf = new SimpleDateFormat("ZZZZ", Locale(""), status); - + if (U_SUCCESS(status)) { UnicodeString inText("GMT$$$"); @@ -4028,7 +4068,7 @@ void DateFormatTest::TestMonthPatterns() { "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 M04 2"), UnicodeString("ren-chen M04bis 2"), UnicodeString("ren-chen M05 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, 2012(ren-chen)"), UnicodeString("Month4bis 2, 2012(ren-chen)"), UnicodeString("Month5 2, 2012(ren-chen)") } }, + { "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)") } }, { "en@calendar=chinese", DateFormat::kShort, { UnicodeString("4/2/2012"), UnicodeString("4bis/2/2012"), UnicodeString("5/2/2012") } }, { "zh@calendar=chinese", DateFormat::kLong, { CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u56DB\\u6708\\u521D\\u4E8C"), CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u95F0\\u56DB\\u6708\\u521D\\u4E8C"), @@ -4052,7 +4092,7 @@ void DateFormatTest::TestMonthPatterns() 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, 2012(29)"), UnicodeString("Month4 2, 2012(29)"), UnicodeString("Month5 1, 2012(29)") } }, + { "en@calendar=dangi", DateFormat::kLong, { UnicodeString("Third Monthbis 2, 2012(29)"), UnicodeString("Fourth Month 2, 2012(29)"), UnicodeString("Fifth Month 1, 2012(29)") } }, { "en@calendar=dangi", DateFormat::kShort, { UnicodeString("3bis/2/2012"), UnicodeString("4/2/2012"), UnicodeString("5/1/2012") } }, { "en@calendar=dangi", -2, { UnicodeString("78x29-3bis-2"), UnicodeString("78x29-4-2"), UnicodeString("78x29-5-1") } }, { "ko@calendar=dangi", DateFormat::kLong, { CharsToUnicodeString("\\uC784\\uC9C4\\uB144 \\uC7243\\uC6D4 2\\uC77C"), @@ -4064,7 +4104,7 @@ void DateFormatTest::TestMonthPatterns() // 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' @@ -4317,6 +4357,67 @@ void DateFormatTest::TestNonGregoFmtParse() } } +typedef struct { + const char* localeID; + DateFormat::EStyle style; + UnicodeString expectPattern; + UnicodeString expectFormat; +} TestFmtWithNumSysItem; +enum { kBBufMax = 128 }; +void DateFormatTest::TestFormatsWithNumberSystems() +{ + LocalPointer zone(TimeZone::createTimeZone(UnicodeString("UTC"))); + const UDate date = 1451556000000.0; // for UTC: grego 31-Dec-2015 10 AM, hebrew 19 tevet 5776, chinese yi-wei 11mo 21day + const TestFmtWithNumSysItem items[] = { + { "haw@calendar=gregorian", DateFormat::kShort, UnicodeString("d/M/yy"), UnicodeString("31/xii/15") }, + { "he@calendar=hebrew", DateFormat::kLong, CharsToUnicodeString("d \\u05D1MMMM y"), CharsToUnicodeString("\\u05D9\\u05F4\\u05D8 \\u05D1\\u05D8\\u05D1\\u05EA \\u05EA\\u05E9\\u05E2\\u05F4\\u05D5") }, // "י״ט בטבת תשע״ו" + { "zh@calendar=chinese", DateFormat::kLong, CharsToUnicodeString("rU\\u5E74MMMd"), CharsToUnicodeString("2015\\u4E59\\u672A\\u5E74\\u51AC\\u6708\\u5EFF\\u4E00") }, // "2015乙未年冬月廿一" + { "zh_Hant@calendar=chinese", DateFormat::kLong, CharsToUnicodeString("rU\\u5E74MMMd"), CharsToUnicodeString("2015\\u4E59\\u672A\\u5E74\\u51AC\\u6708\\u5EFF\\u4E00") }, // "2015乙未年冬月廿一" + { "ja@calendar=chinese", DateFormat::kLong, CharsToUnicodeString("U\\u5E74MMMd\\u65E5"), CharsToUnicodeString("\\u4E59\\u672A\\u5E74\\u5341\\u4E00\\u6708\\u4E8C\\u5341\\u4E00\\u65E5") }, // "乙未年十一月二十一日" + { NULL, DateFormat::kNone, UnicodeString(""), UnicodeString("") }, + }; + const TestFmtWithNumSysItem * itemPtr; + for (itemPtr = items; itemPtr->localeID != NULL; itemPtr++) { + char bExpected[kBBufMax]; + char bResult[kBBufMax]; + UErrorCode status = U_ZERO_ERROR; + Locale locale = Locale::createFromName(itemPtr->localeID); + LocalPointer cal(Calendar::createInstance(zone.orphan(), locale, status)); + if (U_FAILURE(status)) { + dataerrln("Calendar::createInstance fails for locale %s, status %s", itemPtr->localeID, u_errorName(status)); + continue; + } + cal->setTime(date, status); + if (U_FAILURE(status)) { + dataerrln("Calendar::setTime fails for locale %s, date %.1f, status %s", itemPtr->localeID, date, u_errorName(status)); + continue; + } + LocalPointer sdfmt(static_cast(DateFormat::createDateInstance(itemPtr->style, locale))); + if (sdfmt.isNull()) { + dataerrln("DateFormat::createDateInstance fails for locale %s", itemPtr->localeID); + continue; + } + UnicodeString getFormat; + sdfmt->format(*(cal.getAlias()), getFormat, NULL, status); + if (U_FAILURE(status)) { + errln("DateFormat::format fails for locale %s, status %s", itemPtr->localeID, u_errorName(status)); + continue; + } + if (getFormat.compare(itemPtr->expectFormat) != 0) { + itemPtr->expectFormat.extract(0, itemPtr->expectFormat.length(), bExpected, kBBufMax); + getFormat.extract(0, getFormat.length(), bResult, kBBufMax); + errln("DateFormat::format for locale %s, expected \"%s\", got \"%s\"", itemPtr->localeID, bExpected, bResult); + } + UnicodeString getPattern; + sdfmt->toPattern(getPattern); + if (getPattern.compare(itemPtr->expectPattern) != 0) { + itemPtr->expectPattern.extract(0, itemPtr->expectPattern.length(), bExpected, kBBufMax); + getPattern.extract(0, getPattern.length(), bResult, kBBufMax); + errln("DateFormat::toPattern() for locale %s, expected \"%s\", got \"%s\"", itemPtr->localeID, bExpected, bResult); + } + } +} + static const UDate TEST_DATE = 1326585600000.; // 2012-jan-15 void DateFormatTest::TestDotAndAtLeniency() { @@ -4394,7 +4495,7 @@ typedef struct { void DateFormatTest::TestDateFormatLeniency() { // For details see http://bugs.icu-project.org/trac/ticket/10261 - + const UDate july022008 = 1215000001979.0; const TestDateFormatLeniencyItem items[] = { //locale leniency parse String pattern expected result @@ -4405,7 +4506,7 @@ void DateFormatTest::TestDateFormatLeniency() { { "en", true, UnicodeString("2008-Jan--02"), UnicodeString("yyyy-MMM' -- 'dd"), UnicodeString("2008-Jan -- 02") }, { "en", false, UnicodeString("2008-Jan--02"), UnicodeString("yyyy-MMM' -- 'dd"), UnicodeString("") }, // terminator - { NULL, true, UnicodeString(""), UnicodeString(""), UnicodeString("") } + { NULL, true, UnicodeString(""), UnicodeString(""), UnicodeString("") } }; UErrorCode status = U_ZERO_ERROR; LocalPointer cal(Calendar::createInstance(status)); @@ -4417,7 +4518,7 @@ void DateFormatTest::TestDateFormatLeniency() { const TestDateFormatLeniencyItem * itemPtr; LocalPointer sdmft; for (itemPtr = items; itemPtr->locale != NULL; itemPtr++ ) { - + Locale locale = Locale::createFromName(itemPtr->locale); status = U_ZERO_ERROR; ParsePosition pos(0); @@ -4428,37 +4529,37 @@ void DateFormatTest::TestDateFormatLeniency() { } sdmft->setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, itemPtr->leniency, status). setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, itemPtr->leniency, status). - setBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, itemPtr->leniency, status); - UDate d = sdmft->parse(itemPtr->parseString, pos); + setBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, itemPtr->leniency, status); + UDate d = sdmft->parse(itemPtr->parseString, pos); if(itemPtr->expectedResult.length() == 0) { if(pos.getErrorIndex() != -1) { continue; } else { - errln("error: unexpected parse success - " + itemPtr->parseString + - " - pattern " + itemPtr->pattern + - " - error index " + pos.getErrorIndex() + + errln("error: unexpected parse success - " + itemPtr->parseString + + " - pattern " + itemPtr->pattern + + " - error index " + pos.getErrorIndex() + " - leniency " + itemPtr->leniency); continue; } } - if(pos.getErrorIndex() != -1) { - errln("error: parse error for string - " + itemPtr->parseString + - " - pattern " + itemPtr->pattern + - " - idx " + pos.getIndex() + - " - error index "+pos.getErrorIndex() + - " - leniency " + itemPtr->leniency); - continue; + if(pos.getErrorIndex() != -1) { + errln("error: parse error for string - " + itemPtr->parseString + + " - pattern " + itemPtr->pattern + + " - idx " + pos.getIndex() + + " - error index "+pos.getErrorIndex() + + " - leniency " + itemPtr->leniency); + continue; } - UnicodeString formatResult(""); + UnicodeString formatResult(""); sdmft->format(d, formatResult); - if(formatResult.compare(itemPtr->expectedResult) != 0) { - errln("error: unexpected format result. pattern["+itemPtr->pattern+"] expected[" + itemPtr->expectedResult + "] but result was[" + formatResult + "]"); + if(formatResult.compare(itemPtr->expectedResult) != 0) { + errln("error: unexpected format result. pattern["+itemPtr->pattern+"] expected[" + itemPtr->expectedResult + "] but result was[" + formatResult + "]"); continue; - } else { - logln("formatted results match! - " + formatResult); - } + } else { + logln("formatted results match! - " + formatResult); + } } } @@ -4472,36 +4573,36 @@ typedef struct { } TestMultiPatternMatchItem; void DateFormatTest::TestParseMultiPatternMatch() { - // For details see http://bugs.icu-project.org/trac/ticket/10336 + // For details see http://bugs.icu-project.org/trac/ticket/10336 const TestMultiPatternMatchItem items[] = { - // leniency parse String pattern expected result - {true, UnicodeString("2013-Sep 13"), UnicodeString("yyyy-MMM dd"), UnicodeString("2013-Sep 13")}, - {true, UnicodeString("2013-September 14"), UnicodeString("yyyy-MMM dd"), UnicodeString("2013-Sep 14")}, - {false, UnicodeString("2013-September 15"), UnicodeString("yyyy-MMM dd"), UnicodeString("")}, - {false, UnicodeString("2013-September 16"), UnicodeString("yyyy-MMMM dd"), UnicodeString("2013-September 16")}, - {true, UnicodeString("2013-Sep 17"), UnicodeString("yyyy-LLL dd"), UnicodeString("2013-Sep 17")}, - {true, UnicodeString("2013-September 18"), UnicodeString("yyyy-LLL dd"), UnicodeString("2013-Sep 18")}, - {false, UnicodeString("2013-September 19"), UnicodeString("yyyy-LLL dd"), UnicodeString("")}, - {false, UnicodeString("2013-September 20"), UnicodeString("yyyy-LLLL dd"), UnicodeString("2013-September 20")}, - {true, UnicodeString("2013 Sat Sep 21"), UnicodeString("yyyy EEE MMM dd"), UnicodeString("2013 Sat Sep 21")}, - {true, UnicodeString("2013 Sunday Sep 22"), UnicodeString("yyyy EEE MMM dd"), UnicodeString("2013 Sun Sep 22")}, - {false, UnicodeString("2013 Monday Sep 23"), UnicodeString("yyyy EEE MMM dd"), UnicodeString("")}, - {false, UnicodeString("2013 Tuesday Sep 24"), UnicodeString("yyyy EEEE MMM dd"), UnicodeString("2013 Tuesday Sep 24")}, - {true, UnicodeString("2013 Wed Sep 25"), UnicodeString("yyyy eee MMM dd"), UnicodeString("2013 Wed Sep 25")}, - {true, UnicodeString("2013 Thu Sep 26"), UnicodeString("yyyy eee MMM dd"), UnicodeString("2013 Thu Sep 26")}, - {false, UnicodeString("2013 Friday Sep 27"), UnicodeString("yyyy eee MMM dd"), UnicodeString("")}, - {false, UnicodeString("2013 Saturday Sep 28"), UnicodeString("yyyy eeee MMM dd"), UnicodeString("2013 Saturday Sep 28")}, - {true, UnicodeString("2013 Sun Sep 29"), UnicodeString("yyyy ccc MMM dd"), UnicodeString("2013 Sun Sep 29")}, - {true, UnicodeString("2013 Monday Sep 30"), UnicodeString("yyyy ccc MMM dd"), UnicodeString("2013 Mon Sep 30")}, - {false, UnicodeString("2013 Sunday Oct 13"), UnicodeString("yyyy ccc MMM dd"), UnicodeString("")}, - {false, UnicodeString("2013 Monday Oct 14"), UnicodeString("yyyy cccc MMM dd"), UnicodeString("2013 Monday Oct 14")}, - {true, UnicodeString("2013 Oct 15 Q4"), UnicodeString("yyyy MMM dd QQQ"), UnicodeString("2013 Oct 15 Q4")}, - {true, UnicodeString("2013 Oct 16 4th quarter"), UnicodeString("yyyy MMM dd QQQ"), UnicodeString("2013 Oct 16 Q4")}, - {false, UnicodeString("2013 Oct 17 4th quarter"), UnicodeString("yyyy MMM dd QQQ"), UnicodeString("")}, - {false, UnicodeString("2013 Oct 18 Q4"), UnicodeString("yyyy MMM dd QQQ"), UnicodeString("2013 Oct 18 Q4")}, - {true, UnicodeString("2013 Oct 19 Q4"), UnicodeString("yyyy MMM dd qqqq"), UnicodeString("2013 Oct 19 4th quarter")}, - {true, UnicodeString("2013 Oct 20 4th quarter"), UnicodeString("yyyy MMM dd qqqq"), UnicodeString("2013 Oct 20 4th quarter")}, - {false, UnicodeString("2013 Oct 21 Q4"), UnicodeString("yyyy MMM dd qqqq"), UnicodeString("")}, + // leniency parse String pattern expected result + {true, UnicodeString("2013-Sep 13"), UnicodeString("yyyy-MMM dd"), UnicodeString("2013-Sep 13")}, + {true, UnicodeString("2013-September 14"), UnicodeString("yyyy-MMM dd"), UnicodeString("2013-Sep 14")}, + {false, UnicodeString("2013-September 15"), UnicodeString("yyyy-MMM dd"), UnicodeString("")}, + {false, UnicodeString("2013-September 16"), UnicodeString("yyyy-MMMM dd"), UnicodeString("2013-September 16")}, + {true, UnicodeString("2013-Sep 17"), UnicodeString("yyyy-LLL dd"), UnicodeString("2013-Sep 17")}, + {true, UnicodeString("2013-September 18"), UnicodeString("yyyy-LLL dd"), UnicodeString("2013-Sep 18")}, + {false, UnicodeString("2013-September 19"), UnicodeString("yyyy-LLL dd"), UnicodeString("")}, + {false, UnicodeString("2013-September 20"), UnicodeString("yyyy-LLLL dd"), UnicodeString("2013-September 20")}, + {true, UnicodeString("2013 Sat Sep 21"), UnicodeString("yyyy EEE MMM dd"), UnicodeString("2013 Sat Sep 21")}, + {true, UnicodeString("2013 Sunday Sep 22"), UnicodeString("yyyy EEE MMM dd"), UnicodeString("2013 Sun Sep 22")}, + {false, UnicodeString("2013 Monday Sep 23"), UnicodeString("yyyy EEE MMM dd"), UnicodeString("")}, + {false, UnicodeString("2013 Tuesday Sep 24"), UnicodeString("yyyy EEEE MMM dd"), UnicodeString("2013 Tuesday Sep 24")}, + {true, UnicodeString("2013 Wed Sep 25"), UnicodeString("yyyy eee MMM dd"), UnicodeString("2013 Wed Sep 25")}, + {true, UnicodeString("2013 Thu Sep 26"), UnicodeString("yyyy eee MMM dd"), UnicodeString("2013 Thu Sep 26")}, + {false, UnicodeString("2013 Friday Sep 27"), UnicodeString("yyyy eee MMM dd"), UnicodeString("")}, + {false, UnicodeString("2013 Saturday Sep 28"), UnicodeString("yyyy eeee MMM dd"), UnicodeString("2013 Saturday Sep 28")}, + {true, UnicodeString("2013 Sun Sep 29"), UnicodeString("yyyy ccc MMM dd"), UnicodeString("2013 Sun Sep 29")}, + {true, UnicodeString("2013 Monday Sep 30"), UnicodeString("yyyy ccc MMM dd"), UnicodeString("2013 Mon Sep 30")}, + {false, UnicodeString("2013 Sunday Oct 13"), UnicodeString("yyyy ccc MMM dd"), UnicodeString("")}, + {false, UnicodeString("2013 Monday Oct 14"), UnicodeString("yyyy cccc MMM dd"), UnicodeString("2013 Monday Oct 14")}, + {true, UnicodeString("2013 Oct 15 Q4"), UnicodeString("yyyy MMM dd QQQ"), UnicodeString("2013 Oct 15 Q4")}, + {true, UnicodeString("2013 Oct 16 4th quarter"), UnicodeString("yyyy MMM dd QQQ"), UnicodeString("2013 Oct 16 Q4")}, + {false, UnicodeString("2013 Oct 17 4th quarter"), UnicodeString("yyyy MMM dd QQQ"), UnicodeString("")}, + {false, UnicodeString("2013 Oct 18 Q4"), UnicodeString("yyyy MMM dd QQQ"), UnicodeString("2013 Oct 18 Q4")}, + {true, UnicodeString("2013 Oct 19 Q4"), UnicodeString("yyyy MMM dd qqqq"), UnicodeString("2013 Oct 19 4th quarter")}, + {true, UnicodeString("2013 Oct 20 4th quarter"), UnicodeString("yyyy MMM dd qqqq"), UnicodeString("2013 Oct 20 4th quarter")}, + {false, UnicodeString("2013 Oct 21 Q4"), UnicodeString("yyyy MMM dd qqqq"), UnicodeString("")}, {false, UnicodeString("2013 Oct 22 4th quarter"), UnicodeString("yyyy MMM dd qqqq"), UnicodeString("2013 Oct 22 4th quarter")}, {false, UnicodeString("--end--"), UnicodeString(""), UnicodeString("")}, }; @@ -4527,30 +4628,30 @@ void DateFormatTest::TestParseMultiPatternMatch() { continue; } sdmft->setBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, itemPtr->leniency, status); - UDate d = sdmft->parse(itemPtr->parseString, pos); - + UDate d = sdmft->parse(itemPtr->parseString, pos); + if(itemPtr->expectedResult.length() == 0) { if(pos.getErrorIndex() != -1) { continue; } else { - errln("error: unexpected parse success - " + itemPtr->parseString + - " - error index " + pos.getErrorIndex() + + errln("error: unexpected parse success - " + itemPtr->parseString + + " - error index " + pos.getErrorIndex() + " - leniency " + itemPtr->leniency); continue; } } - if(pos.getErrorIndex() != -1) { - errln("error: parse error for string - " +itemPtr->parseString + " -- idx["+pos.getIndex()+"] errIdx["+pos.getErrorIndex()+"]"); - continue; + if(pos.getErrorIndex() != -1) { + errln("error: parse error for string - " +itemPtr->parseString + " -- idx["+pos.getIndex()+"] errIdx["+pos.getErrorIndex()+"]"); + continue; } - UnicodeString formatResult(""); + UnicodeString formatResult(""); sdmft->format(d, formatResult); - if(formatResult.compare(itemPtr->expectedResult) != 0) { - errln("error: unexpected format result. expected[" + itemPtr->expectedResult + "] but result was[" + formatResult + "]"); - } else { - logln("formatted results match! - " + formatResult); - } + if(formatResult.compare(itemPtr->expectedResult) != 0) { + errln("error: unexpected format result. expected[" + itemPtr->expectedResult + "] but result was[" + formatResult + "]"); + } else { + logln("formatted results match! - " + formatResult); + } } delete sdmft; } @@ -4568,7 +4669,7 @@ void DateFormatTest::TestParseLeniencyAPIs() { assertTrue("isCalendarLenient default", fmt->isCalendarLenient()); assertTrue("ALLOW_WHITESPACE default", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)); assertTrue("ALLOW_NUMERIC default", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)); - assertTrue("PARTIAL_MATCH default", fmt->getBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, status)); + assertTrue("PARTIAL_MATCH default", fmt->getBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, status)); assertTrue("MULTIPLE_PATTERNS default", fmt->getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status)); // Set calendar to strict @@ -4587,7 +4688,7 @@ void DateFormatTest::TestParseLeniencyAPIs() { assertFalse("ALLOW_WHITESPACE after setLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)); assertFalse("ALLOW_NUMERIC after setLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)); // These two boolean attributes are NOT affected according to the API specification - assertTrue("PARTIAL_MATCH after setLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, status)); + assertTrue("PARTIAL_MATCH after setLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, status)); assertTrue("MULTIPLE_PATTERNS after setLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status)); // Allow white space leniency @@ -4639,12 +4740,12 @@ void DateFormatTest::TestNumberFormatOverride() { { "MdMMd", "\\u521D\\u516D \\u5341\\u4E94"}, { "mixed", "\\u521D\\u516D \\u5341\\u4E94"} }; - + UDate test_date = date(97, 6 - 1, 15); - for(int i=0; i < (int)(sizeof(DATA)/sizeof(DATA[0])); i++){ + for(int i=0; i < UPRV_LENGTHOF(DATA); i++){ fields = DATA[i][0]; - + LocalPointer fmt; fmt.adoptInsteadAndCheckErrorCode(new SimpleDateFormat((UnicodeString)"MM d", status), status); assertSuccess("SimpleDateFormat with pattern MM d", status); @@ -4660,7 +4761,7 @@ void DateFormatTest::TestNumberFormatOverride() { fields = (UnicodeString) "M"; fmt->adoptNumberFormat(fields, singleOverrideNF, status); assertSuccess("adoptNumberFormat singleOverrideNF", status); - + fmt->adoptNumberFormat(overrideNF); } else if (fields == (UnicodeString) "Mo"){ // o is invlid field fmt->adoptNumberFormat(fields, overrideNF, status); @@ -4679,7 +4780,7 @@ void DateFormatTest::TestNumberFormatOverride() { UnicodeString expected = ((UnicodeString)DATA[i][1]).unescape();; - if (result != expected) + if (result != expected) errln("FAIL: Expected " + expected + " get: " + result); } } @@ -4806,6 +4907,622 @@ void DateFormatTest::TestChangeCalendar() { assertEquals("format yMMMd", "Iyar 29, 5758", result); } +void DateFormatTest::TestPatternFromSkeleton() { + static const struct { + const Locale& locale; + const char* const skeleton; + const char* const pattern; + } TESTDATA[] = { + // Ticket #11985 + {Locale::getEnglish(), "jjmm", "h:mm a"}, + {Locale::getEnglish(), "JJmm", "hh:mm"}, + {Locale::getGerman(), "jjmm", "HH:mm"}, + {Locale::getGerman(), "JJmm", "HH:mm"} + }; + + for (size_t i = 0; i < UPRV_LENGTHOF(TESTDATA); i++) { + UErrorCode status = U_ZERO_ERROR; + LocalPointer fmt( + DateFormat::createInstanceForSkeleton( + TESTDATA[i].skeleton, TESTDATA[i].locale, status)); + if (!assertSuccess("createInstanceForSkeleton", status)) { + return; + } + UnicodeString pattern; + static_cast(fmt.getAlias())->toPattern(pattern); + assertEquals("Format pattern", TESTDATA[i].pattern, pattern); + } +} + +void DateFormatTest::TestAmPmMidnightNoon() { + // Some times on 2015-11-13 (UTC+0). + UDate k000000 = 1447372800000.0; + UDate k000030 = 1447372830000.0; + UDate k003000 = 1447374600000.0; + UDate k060000 = 1447394400000.0; + UDate k120000 = 1447416000000.0; + UDate k180000 = 1447437600000.0; + + UErrorCode errorCode = U_ZERO_ERROR; + SimpleDateFormat sdf(UnicodeString(), errorCode); + if (U_FAILURE(errorCode)) { + dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode)); + return; + } + const TimeZone *tz = TimeZone::getGMT(); + sdf.setTimeZone(*tz); + UnicodeString out; + + // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day. + // For ICU 57 output of "midnight" is temporarily suppressed. + + // Short. + sdf.applyPattern(UnicodeString("hh:mm:ss bbb")); + + // assertEquals("hh:mm:ss bbb | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss bbb | 00:00:00", "12:00:00 AM", sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss bbb | 00:00:30", "12:00:30 AM", sdf.format(k000030, out.remove())); + assertEquals("hh:mm:ss bbb | 00:30:00", "12:30:00 AM", sdf.format(k003000, out.remove())); + assertEquals("hh:mm:ss bbb | 06:00:00", "06:00:00 AM", sdf.format(k060000, out.remove())); + assertEquals("hh:mm:ss bbb | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove())); + assertEquals("hh:mm:ss bbb | 18:00:00", "06:00:00 PM", sdf.format(k180000, out.remove())); + + sdf.applyPattern(UnicodeString("hh:mm bbb")); + + // assertEquals("hh:mm bbb | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove())); + assertEquals("hh:mm bbb | 00:00:00", "12:00 AM", sdf.format(k000000, out.remove())); + // assertEquals("hh:mm bbb | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove())); + assertEquals("hh:mm bbb | 00:00:30", "12:00 AM", sdf.format(k000030, out.remove())); + assertEquals("hh:mm bbb | 00:30:00", "12:30 AM", sdf.format(k003000, out.remove())); + + sdf.applyPattern(UnicodeString("hh bbb")); + + // assertEquals("hh bbb | 00:00:00", "12 midnight", sdf.format(k000000, out.remove())); + assertEquals("hh bbb | 00:00:00", "12 AM", sdf.format(k000000, out.remove())); + // assertEquals("hh bbb | 00:00:30", "12 midnight", sdf.format(k000030, out.remove())); + assertEquals("hh bbb | 00:00:30", "12 AM", sdf.format(k000030, out.remove())); + // assertEquals("hh bbb | 00:30:00", "12 midnight", sdf.format(k003000, out.remove())); + assertEquals("hh bbb | 00:30:00", "12 AM", sdf.format(k003000, out.remove())); + + // Wide. + sdf.applyPattern(UnicodeString("hh:mm:ss bbbb")); + + // assertEquals("hh:mm:ss bbbb | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss bbbb | 00:00:00", "12:00:00 AM", sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss bbbb | 00:00:30", "12:00:30 AM", sdf.format(k000030, out.remove())); + assertEquals("hh:mm:ss bbbb | 00:30:00", "12:30:00 AM", sdf.format(k003000, out.remove())); + assertEquals("hh:mm:ss bbbb | 06:00:00", "06:00:00 AM", sdf.format(k060000, out.remove())); + assertEquals("hh:mm:ss bbbb | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove())); + assertEquals("hh:mm:ss bbbb | 18:00:00", "06:00:00 PM", sdf.format(k180000, out.remove())); + + sdf.applyPattern(UnicodeString("hh:mm bbbb")); + + // assertEquals("hh:mm bbbb | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove())); + assertEquals("hh:mm bbbb | 00:00:00", "12:00 AM", sdf.format(k000000, out.remove())); + // assertEquals("hh:mm bbbb | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove())); + assertEquals("hh:mm bbbb | 00:00:30", "12:00 AM", sdf.format(k000030, out.remove())); + assertEquals("hh:mm bbbb | 00:30:00", "12:30 AM", sdf.format(k003000, out.remove())); + + sdf.applyPattern(UnicodeString("hh bbbb")); + + // assertEquals("hh bbbb | 00:00:00", "12 midnight", sdf.format(k000000, out.remove())); + assertEquals("hh bbbb | 00:00:00", "12 AM", sdf.format(k000000, out.remove())); + // assertEquals("hh bbbb | 00:00:30", "12 midnight", sdf.format(k000030, out.remove())); + assertEquals("hh bbbb | 00:00:30", "12 AM", sdf.format(k000030, out.remove())); + // assertEquals("hh bbbb | 00:30:00", "12 midnight", sdf.format(k003000, out.remove())); + assertEquals("hh bbbb | 00:30:00", "12 AM", sdf.format(k003000, out.remove())); + + // Narrow. + sdf.applyPattern(UnicodeString("hh:mm:ss bbbbb")); + + // assertEquals("hh:mm:ss bbbbb | 00:00:00", "12:00:00 mi", sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss bbbbb | 00:00:00", "12:00:00 a", sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss bbbbb | 00:00:30", "12:00:30 a", sdf.format(k000030, out.remove())); + assertEquals("hh:mm:ss bbbbb | 00:30:00", "12:30:00 a", sdf.format(k003000, out.remove())); + assertEquals("hh:mm:ss bbbbb | 06:00:00", "06:00:00 a", sdf.format(k060000, out.remove())); + assertEquals("hh:mm:ss bbbbb | 12:00:00", "12:00:00 n", sdf.format(k120000, out.remove())); + assertEquals("hh:mm:ss bbbbb | 18:00:00", "06:00:00 p", sdf.format(k180000, out.remove())); + + sdf.applyPattern(UnicodeString("hh:mm bbbbb")); + + // assertEquals("hh:mm bbbbb | 00:00:00", "12:00 mi", sdf.format(k000000, out.remove())); + assertEquals("hh:mm bbbbb | 00:00:00", "12:00 a", sdf.format(k000000, out.remove())); + // assertEquals("hh:mm bbbbb | 00:00:30", "12:00 mi", sdf.format(k000030, out.remove())); + assertEquals("hh:mm bbbbb | 00:00:30", "12:00 a", sdf.format(k000030, out.remove())); + assertEquals("hh:mm bbbbb | 00:30:00", "12:30 a", sdf.format(k003000, out.remove())); + + sdf.applyPattern(UnicodeString("hh bbbbb")); + + // assertEquals("hh bbbbb | 00:00:00", "12 mi", sdf.format(k000000, out.remove())); + assertEquals("hh bbbbb | 00:00:00", "12 a", sdf.format(k000000, out.remove())); + // assertEquals("hh bbbbb | 00:00:30", "12 mi", sdf.format(k000030, out.remove())); + assertEquals("hh bbbbb | 00:00:30", "12 a", sdf.format(k000030, out.remove())); + // assertEquals("hh bbbbb | 00:30:00", "12 mi", sdf.format(k003000, out.remove())); + assertEquals("hh bbbbb | 00:30:00", "12 a", sdf.format(k003000, out.remove())); +} + +void DateFormatTest::TestFlexibleDayPeriod() { + // Some times on 2015-11-13 (UTC+0). + UDate k000000 = 1447372800000.0; + UDate k000030 = 1447372830000.0; + UDate k003000 = 1447374600000.0; + UDate k060000 = 1447394400000.0; + UDate k120000 = 1447416000000.0; + UDate k180000 = 1447437600000.0; + + UErrorCode errorCode = U_ZERO_ERROR; + SimpleDateFormat sdf(UnicodeString(), errorCode); + if (U_FAILURE(errorCode)) { + dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode)); + return; + } + const TimeZone *tz = TimeZone::getGMT(); + sdf.setTimeZone(*tz); + UnicodeString out; + + // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day. + // For ICU 57 output of "midnight" is temporarily suppressed. + + // Short. + sdf.applyPattern(UnicodeString("hh:mm:ss BBB")); + + // assertEquals("hh:mm:ss BBB | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss BBB | 00:00:00", "12:00:00 at night", sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss BBB | 00:00:30", "12:00:30 at night", sdf.format(k000030, out.remove())); + assertEquals("hh:mm:ss BBB | 00:30:00", "12:30:00 at night", sdf.format(k003000, out.remove())); + assertEquals("hh:mm:ss BBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000, out.remove())); + assertEquals("hh:mm:ss BBB | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove())); + assertEquals("hh:mm:ss BBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000, out.remove())); + + sdf.applyPattern(UnicodeString("hh:mm BBB")); + + // assertEquals("hh:mm BBB | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove())); + assertEquals("hh:mm BBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove())); + // assertEquals("hh:mm BBB | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove())); + assertEquals("hh:mm BBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove())); + assertEquals("hh:mm BBB | 00:30:00", "12:30 at night", sdf.format(k003000, out.remove())); + + sdf.applyPattern(UnicodeString("hh BBB")); + + // assertEquals("hh BBB | 00:00:00", "12 midnight", sdf.format(k000000, out.remove())); + assertEquals("hh BBB | 00:00:30", "12 at night", sdf.format(k000030, out.remove())); + // assertEquals("hh BBB | 00:00:30", "12 midnight", sdf.format(k000030, out.remove())); + assertEquals("hh BBB | 00:00:30", "12 at night", sdf.format(k000030, out.remove())); + // assertEquals("hh BBB | 00:30:00", "12 midnight", sdf.format(k003000, out.remove())); + assertEquals("hh BBB | 00:30:00", "12 at night", sdf.format(k003000, out.remove())); + + // Wide. + sdf.applyPattern(UnicodeString("hh:mm:ss BBBB")); + + // assertEquals("hh:mm:ss BBBB | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss BBBB | 00:00:00", "12:00:00 at night", sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss BBBB | 00:00:30", "12:00:30 at night", sdf.format(k000030, out.remove())); + assertEquals("hh:mm:ss BBBB | 00:30:00", "12:30:00 at night", sdf.format(k003000, out.remove())); + assertEquals("hh:mm:ss BBBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000, out.remove())); + assertEquals("hh:mm:ss BBBB | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove())); + assertEquals("hh:mm:ss BBBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000, out.remove())); + + sdf.applyPattern(UnicodeString("hh:mm BBBB")); + + // assertEquals("hh:mm BBBB | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove())); + assertEquals("hh:mm BBBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove())); + // assertEquals("hh:mm BBBB | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove())); + assertEquals("hh:mm BBBB | 00:00:30", "12:00 at night", sdf.format(k000030, out.remove())); + assertEquals("hh:mm BBBB | 00:30:00", "12:30 at night", sdf.format(k003000, out.remove())); + + sdf.applyPattern(UnicodeString("hh BBBB")); + + // assertEquals("hh BBBB | 00:00:00", "12 midnight", sdf.format(k000000, out.remove())); + assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove())); + // assertEquals("hh BBBB | 00:00:30", "12 midnight", sdf.format(k000030, out.remove())); + assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove())); + // assertEquals("hh BBBB | 00:80:00", "12 midnight", sdf.format(k003000, out.remove())); + assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove())); + + // Narrow. + sdf.applyPattern(UnicodeString("hh:mm:ss BBBBB")); + + // assertEquals("hh:mm:ss BBBBB | 00:00:00", "12:00:00 mi", sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss BBBBB | 00:00:00", "12:00:00 at night", sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss BBBBB | 00:00:30", "12:00:30 at night", sdf.format(k000030, out.remove())); + assertEquals("hh:mm:ss BBBBB | 00:30:00", "12:30:00 at night", sdf.format(k003000, out.remove())); + assertEquals("hh:mm:ss BBBBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000, out.remove())); + assertEquals("hh:mm:ss BBBBB | 12:00:00", "12:00:00 n", sdf.format(k120000, out.remove())); + assertEquals("hh:mm:ss BBBBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000, out.remove())); + + sdf.applyPattern(UnicodeString("hh:mm BBBBB")); + + // assertEquals("hh:mm BBBBB | 00:00:00", "12:00 mi", sdf.format(k000000, out.remove())); + assertEquals("hh:mm BBBBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove())); + // assertEquals("hh:mm BBBBB | 00:00:30", "12:00 mi", sdf.format(k000030, out.remove())); + assertEquals("hh:mm BBBBB | 00:00:30", "12:00 at night", sdf.format(k000030, out.remove())); + assertEquals("hh:mm BBBBB | 00:30:00", "12:30 at night", sdf.format(k003000, out.remove())); + + sdf.applyPattern(UnicodeString("hh BBBBB")); + + // assertEquals("hh BBBBB | 00:00:00", "12 mi", sdf.format(k000000, out.remove())); + assertEquals("hh BBBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove())); + // assertEquals("hh BBBBB | 00:00:30", "12 mi", sdf.format(k000030, out.remove())); + assertEquals("hh BBBBB | 00:00:30", "12 at night", sdf.format(k000030, out.remove())); + // assertEquals("hh BBBBB | 00:30:00", "12 mi", sdf.format(k003000, out.remove())); + assertEquals("hh BBBBB | 00:30:00", "12 at night", sdf.format(k003000, out.remove())); +} + +void DateFormatTest::TestDayPeriodWithLocales() { + // Some times on 2015-11-13 (UTC+0). + UDate k000000 = 1447372800000.0; + UDate k010000 = 1447376400000.0; + UDate k120000 = 1447416000000.0; + UDate k220000 = 1447452000000.0; + + UErrorCode errorCode = U_ZERO_ERROR; + const TimeZone *tz = TimeZone::getGMT(); + UnicodeString out; + + // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day. + // For ICU 57 output of "midnight" and its localized equivalentns is temporarily suppressed. + + // Locale de has a word for midnight, but not noon. + SimpleDateFormat sdf(UnicodeString(), Locale::getGermany(), errorCode); + if (U_FAILURE(errorCode)) { + dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode)); + return; + } + sdf.setTimeZone(*tz); + + sdf.applyPattern(UnicodeString("hh:mm:ss bbbb")); + + // assertEquals("hh:mm:ss bbbb | 00:00:00 | de", "12:00:00 Mitternacht", + // sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss bbbb | 00:00:00 | de", "12:00:00 AM" /* change for Apple data */, + sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss bbbb | 12:00:00 | de", "12:00:00 PM" /* change for Apple data */, + sdf.format(k120000, out.remove())); + + // Locale ee has a rule that wraps around midnight (21h - 4h). + sdf = SimpleDateFormat(UnicodeString(), Locale("ee"), errorCode); + sdf.setTimeZone(*tz); + + sdf.applyPattern(UnicodeString("hh:mm:ss BBBB")); + + assertEquals("hh:mm:ss BBBB | 22:00:00 | ee", UnicodeString("10:00:00 z\\u00E3").unescape(), + sdf.format(k220000, out.remove())); + assertEquals("hh:mm:ss BBBB | 00:00:00 | ee", UnicodeString("12:00:00 z\\u00E3").unescape(), + sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss BBBB | 01:00:00 | ee", UnicodeString("01:00:00 z\\u00E3").unescape(), + sdf.format(k010000, out.remove())); + + // Locale root has rules for AM/PM only. + sdf = SimpleDateFormat(UnicodeString(), Locale("root"), errorCode); + sdf.setTimeZone(*tz); + + sdf.applyPattern(UnicodeString("hh:mm:ss BBBB")); + + assertEquals("hh:mm:ss BBBB | 00:00:00 | root", "12:00:00 AM", + sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss BBBB | 12:00:00 | root", "12:00:00 PM", + sdf.format(k120000, out.remove())); + + // Empty string should behave exactly as root. + sdf = SimpleDateFormat(UnicodeString(), Locale(""), errorCode); + sdf.setTimeZone(*tz); + + sdf.applyPattern(UnicodeString("hh:mm:ss BBBB")); + + assertEquals("hh:mm:ss BBBB | 00:00:00 | \"\" (root)", "12:00:00 AM", + sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss BBBB | 12:00:00 | \"\" (root)", "12:00:00 PM", + sdf.format(k120000, out.remove())); + + // Locale en_US should fall back to en. + sdf = SimpleDateFormat(UnicodeString(), Locale("en_US"), errorCode); + sdf.setTimeZone(*tz); + + sdf.applyPattern(UnicodeString("hh:mm:ss BBBB")); + + // assertEquals("hh:mm:ss BBBB | 00:00:00 | en_US", "12:00:00 midnight", + // sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss BBBB | 00:00:00 | en_US", "12:00:00 at night", + sdf.format(k000000, out.remove())); + assertEquals("hh:mm:ss BBBB | 01:00:00 | en_US", "01:00:00 at night", + sdf.format(k010000, out.remove())); + assertEquals("hh:mm:ss BBBB | 12:00:00 | en_US", "12:00:00 noon", + sdf.format(k120000, out.remove())); + + // Locale es_CO should not fall back to es and should have a + // different string for 1 in the morning. + // (es_CO: "de la manana" (first n has a tilde) vs. es: "de la madrugada") + sdf = SimpleDateFormat(UnicodeString(), Locale("es_CO"), errorCode); + sdf.setTimeZone(*tz); + + sdf.applyPattern(UnicodeString("hh:mm:ss BBBB")); + assertEquals("hh:mm:ss BBBB | 01:00:00 | es_CO", UnicodeString("01:00:00 de la ma\\u00F1ana").unescape(), + sdf.format(k010000, out.remove())); + + sdf = SimpleDateFormat(UnicodeString(), Locale("es"), errorCode); + sdf.setTimeZone(*tz); + + sdf.applyPattern(UnicodeString("hh:mm:ss BBBB")); + assertEquals("hh:mm:ss BBBB | 01:00:00 | es", "01:00:00 de la madrugada", + sdf.format(k010000, out.remove())); +} + +void DateFormatTest::TestMinuteSecondFieldsInOddPlaces() { + // Some times on 2015-11-13 (UTC+0). + UDate k000000 = 1447372800000.0; + UDate k000030 = 1447372830000.0; + UDate k003000 = 1447374600000.0; + UDate k060030 = 1447394430000.0; + UDate k063000 = 1447396200000.0; + + UErrorCode errorCode = U_ZERO_ERROR; + const TimeZone *tz = TimeZone::getGMT(); + UnicodeString out; + + // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day. + // For ICU 57 output of "midnight" is temporarily suppressed. + + // Seconds field is not present. + + // Apply pattern through constructor to make sure parsePattern() is called during initialization. + SimpleDateFormat sdf(UnicodeString("hh:mm 'ss' bbbb"), errorCode); + if (U_FAILURE(errorCode)) { + dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode)); + return; + } + sdf.setTimeZone(*tz); + + // assertEquals("hh:mm 'ss' bbbb | 00:00:30", "12:00 ss midnight", + // sdf.format(k000030, out.remove())); + assertEquals("hh:mm 'ss' bbbb | 00:00:30", "12:00 ss AM", + sdf.format(k000030, out.remove())); + assertEquals("hh:mm 'ss' bbbb | 06:00:30", "06:00 ss AM", + sdf.format(k060030, out.remove())); + + sdf.applyPattern(UnicodeString("hh:mm 'ss' BBBB")); + + // assertEquals("hh:mm 'ss' BBBB | 00:00:30", "12:00 ss midnight", + // sdf.format(k000030, out.remove())); + assertEquals("hh:mm 'ss' BBBB | 00:00:30", "12:00 ss at night", + sdf.format(k000030, out.remove())); + assertEquals("hh:mm 'ss' BBBB | 06:00:30", "06:00 ss in the morning", + sdf.format(k060030, out.remove())); + + // Minutes field is not present. + sdf.applyPattern(UnicodeString("hh 'mm ss' bbbb")); + + // assertEquals("hh 'mm ss' bbbb | 00:30:00", "12 mm ss midnight", + // sdf.format(k003000, out.remove())); + assertEquals("hh 'mm ss' bbbb | 00:30:00", "12 mm ss AM", + sdf.format(k003000, out.remove())); + assertEquals("hh 'mm ss' bbbb | 06:30:00", "06 mm ss AM", + sdf.format(k063000, out.remove())); + + sdf.applyPattern(UnicodeString("hh 'mm ss' BBBB")); + + // assertEquals("hh 'mm ss' BBBB | 00:30:00", "12 mm ss midnight", + // sdf.format(k003000, out.remove())); + assertEquals("hh 'mm ss' BBBB | 00:30:00", "12 mm ss at night", + sdf.format(k003000, out.remove())); + assertEquals("hh 'mm ss' BBBB | 06:30:00", "06 mm ss in the morning", + sdf.format(k063000, out.remove())); + + // Minutes and seconds fields appear after day periods. + sdf.applyPattern(UnicodeString("bbbb hh:mm:ss")); + + // assertEquals("bbbb hh:mm:ss | 00:00:00", "midnight 12:00:00", + // sdf.format(k000000, out.remove())); + assertEquals("bbbb hh:mm:ss | 00:00:00", "AM 12:00:00", + sdf.format(k000000, out.remove())); + assertEquals("bbbb hh:mm:ss | 00:00:30", "AM 12:00:30", + sdf.format(k000030, out.remove())); + assertEquals("bbbb hh:mm:ss | 00:30:00", "AM 12:30:00", + sdf.format(k003000, out.remove())); + + sdf.applyPattern(UnicodeString("BBBB hh:mm:ss")); + + // assertEquals("BBBB hh:mm:ss | 00:00:00", "midnight 12:00:00", + // sdf.format(k000000, out.remove())); + assertEquals("BBBB hh:mm:ss | 00:00:00", "at night 12:00:00", + sdf.format(k000000, out.remove())); + assertEquals("BBBB hh:mm:ss | 00:00:30", "at night 12:00:30", + sdf.format(k000030, out.remove())); + assertEquals("BBBB hh:mm:ss | 00:30:00", "at night 12:30:00", + sdf.format(k003000, out.remove())); + + // Confirm applyPattern() reparses the pattern string. + sdf.applyPattern(UnicodeString("BBBB hh")); + // assertEquals("BBBB hh | 00:00:30", "midnight 12", + // sdf.format(k000030, out.remove())); + assertEquals("BBBB hh | 00:00:30", "at night 12", + sdf.format(k000030, out.remove())); + + sdf.applyPattern(UnicodeString("BBBB hh:mm:'ss'")); + // assertEquals("BBBB hh:mm:'ss' | 00:00:30", "midnight 12:00:ss", + // sdf.format(k000030, out.remove())); + assertEquals("BBBB hh | 00:00:30", "at night 12:00:ss", + sdf.format(k000030, out.remove())); + + sdf.applyPattern(UnicodeString("BBBB hh:mm:ss")); + assertEquals("BBBB hh:mm:ss | 00:00:30", "at night 12:00:30", + sdf.format(k000030, out.remove())); +} + +void DateFormatTest::TestDayPeriodParsing() { + // Some times on 2015-11-13 (UTC+0). + UDate k000000 = 1447372800000.0; + UDate k003700 = 1447375020000.0; + UDate k010000 = 1447376400000.0; + UDate k013000 = 1447378200000.0; + UDate k030000 = 1447383600000.0; + UDate k090000 = 1447405200000.0; + UDate k120000 = 1447416000000.0; + UDate k130000 = 1447419600000.0; + UDate k133700 = 1447421820000.0; + UDate k150000 = 1447426800000.0; + UDate k190000 = 1447441200000.0; + UDate k193000 = 1447443000000.0; + UDate k200000 = 1447444800000.0; + UDate k210000 = 1447448400000.0; + + UErrorCode errorCode = U_ZERO_ERROR; + SimpleDateFormat sdf(UnicodeString(), errorCode); + if (U_FAILURE(errorCode)) { + dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode)); + return; + } + const TimeZone *tz = TimeZone::getGMT(); + sdf.setTimeZone(*tz); + UnicodeString out; + + // 'B' -- flexible day periods + // A day period on its own parses to the center of that period. + sdf.applyPattern(UnicodeString("yyyy-MM-dd B")); + assertEquals("yyyy-MM-dd B | 2015-11-13 midnight", + k000000, sdf.parse(UnicodeString("2015-11-13 midnight"), errorCode)); + assertEquals("yyyy-MM-dd B | 2015-11-13 noon", + k120000, sdf.parse(UnicodeString("2015-11-13 noon"), errorCode)); + assertEquals("yyyy-MM-dd B | 2015-11-13 in the afternoon", + k150000, sdf.parse(UnicodeString("2015-11-13 in the afternoon"), errorCode)); + assertEquals("yyyy-MM-dd B | 2015-11-13 in the evening", + k193000, sdf.parse(UnicodeString("2015-11-13 in the evening"), errorCode)); + assertEquals("yyyy-MM-dd B | 2015-11-13 at night", + k013000, sdf.parse(UnicodeString("2015-11-13 at night"), errorCode)); + + // If time and day period are consistent with each other then time is parsed accordingly. + sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm B")); + assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 12:00 midnight", + k000000, sdf.parse(UnicodeString("2015-11-13 12:00 midnight"), errorCode)); + assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 12:00 noon", + k120000, sdf.parse(UnicodeString("2015-11-13 12:00 noon"), errorCode)); + assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 01:00 at night", + k010000, sdf.parse(UnicodeString("2015-11-13 01:00 at night"), errorCode)); + assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 01:00 in the afternoon", + k130000, sdf.parse(UnicodeString("2015-11-13 01:00 in the afternoon"), errorCode)); + assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 09:00 in the morning", + k090000, sdf.parse(UnicodeString("2015-11-13 09:00 in the morning"), errorCode)); + assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 09:00 at night", + k210000, sdf.parse(UnicodeString("2015-11-13 09:00 at night"), errorCode)); + + // If the hour is 13 thru 23 then day period has no effect on time (since time is assumed + // to be in 24-hour format). + sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm B")); + assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 midnight", + k133700, sdf.parse(UnicodeString("2015-11-13 13:37 midnight"), errorCode)); + assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 noon", + k133700, sdf.parse(UnicodeString("2015-11-13 13:37 noon"), errorCode)); + assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 at night", + k133700, sdf.parse(UnicodeString("2015-11-13 13:37 at night"), errorCode)); + assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 in the afternoon", + k133700, sdf.parse(UnicodeString("2015-11-13 13:37 in the afternoon"), errorCode)); + assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 in the morning", + k133700, sdf.parse(UnicodeString("2015-11-13 13:37 in the morning"), errorCode)); + assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 at night", + k133700, sdf.parse(UnicodeString("2015-11-13 13:37 at night"), errorCode)); + + // Hour 0 is synonymous with hour 12 when parsed with 'h'. + // This unfortunately means we have to tolerate "0 noon" as it's synonymous with "12 noon". + sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm B")); + assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 00:00 midnight", + k000000, sdf.parse(UnicodeString("2015-11-13 00:00 midnight"), errorCode)); + assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 00:00 noon", + k120000, sdf.parse(UnicodeString("2015-11-13 00:00 noon"), errorCode)); + + // But when parsed with 'H', 0 indicates a 24-hour time, therefore we disregard the day period. + sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm B")); + assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 midnight", + k003700, sdf.parse(UnicodeString("2015-11-13 00:37 midnight"), errorCode)); + assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 noon", + k003700, sdf.parse(UnicodeString("2015-11-13 00:37 noon"), errorCode)); + assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 at night", + k003700, sdf.parse(UnicodeString("2015-11-13 00:37 at night"), errorCode)); + assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 in the afternoon", + k003700, sdf.parse(UnicodeString("2015-11-13 00:37 in the afternoon"), errorCode)); + assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 in the morning", + k003700, sdf.parse(UnicodeString("2015-11-13 00:37 in the morning"), errorCode)); + assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 at night", + k003700, sdf.parse(UnicodeString("2015-11-13 00:37 at night"), errorCode)); + + // Even when parsed with 'H', hours 1 thru 12 are considered 12-hour time and takes + // day period into account in parsing. + sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm B")); + assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 12:00 midnight", + k000000, sdf.parse(UnicodeString("2015-11-13 12:00 midnight"), errorCode)); + assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 12:00 noon", + k120000, sdf.parse(UnicodeString("2015-11-13 12:00 noon"), errorCode)); + assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 01:00 at night", + k010000, sdf.parse(UnicodeString("2015-11-13 01:00 at night"), errorCode)); + assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 01:00 in the afternoon", + k130000, sdf.parse(UnicodeString("2015-11-13 01:00 in the afternoon"), errorCode)); + assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 09:00 in the morning", + k090000, sdf.parse(UnicodeString("2015-11-13 09:00 in the morning"), errorCode)); + assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 09:00 at night", + k210000, sdf.parse(UnicodeString("2015-11-13 09:00 at night"), errorCode)); + + // If a 12-hour time and the day period don't agree with each other, time is parsed as close + // to the given day period as possible. + sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm B")); + + // AFTERNOON1 is [12, 18), but "7 in the afternoon" parses to 19:00. + assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 07:00 in the afternoon", + k190000, sdf.parse(UnicodeString("2015-11-13 07:00 in the afternoon"), errorCode)); + // NIGHT1 is [21, 6), but "8 at night" parses to 20:00. + assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 08:00 at night", + k200000, sdf.parse(UnicodeString("2015-11-13 08:00 at night"), errorCode)); + + // 'b' -- fixed day periods (AM, PM, midnight, noon) + // On their own, "midnight" parses to 00:00 and "noon" parses to 12:00. + // AM and PM are handled by the 'a' parser (which doesn't handle this case well). + sdf.applyPattern(UnicodeString("yyyy-MM-dd b")); + assertEquals("yyyy-MM-dd b | 2015-11-13 midnight", + k000000, sdf.parse(UnicodeString("2015-11-13 midnight"), errorCode)); + assertEquals("yyyy-MM-dd b | 2015-11-13 noon", + k120000, sdf.parse(UnicodeString("2015-11-13 noon"), errorCode)); + + // For 12-hour times, AM and PM should be parsed as if with pattern character 'a'. + sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm b")); + assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 01:00 AM", + k010000, sdf.parse(UnicodeString("2015-11-13 01:00 AM"), errorCode)); + assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 01:00 PM", + k130000, sdf.parse(UnicodeString("2015-11-13 01:00 PM"), errorCode)); + + // 12 midnight parses to 00:00, and 12 noon parses to 12:00. + assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 12:00 midnight", + k000000, sdf.parse(UnicodeString("2015-11-13 12:00 midnight"), errorCode)); + assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 12:00 noon", + k120000, sdf.parse(UnicodeString("2015-11-13 12:00 noon"), errorCode)); + + // Hours 13-23 indicate 24-hour time so we disregard "midnight" or "noon". + // Again, AM and PM are handled by the 'a' parser which doesn't handle this case well. + sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm b")); + assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 13:37 midnight", + k133700, sdf.parse(UnicodeString("2015-11-13 13:37 midnight"), errorCode)); + assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 13:37 noon", + k133700, sdf.parse(UnicodeString("2015-11-13 13:37 noon"), errorCode)); + + // Hour 0 is synonymous with hour 12 when parsed with 'h'. + // Again, this means we have to tolerate "0 noon" as it's synonymous with "12 noon". + sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm b")); + assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 00:00 midnight", + k000000, sdf.parse(UnicodeString("2015-11-13 00:00 midnight"), errorCode)); + assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 00:00 noon", + k120000, sdf.parse(UnicodeString("2015-11-13 00:00 noon"), errorCode)); + + // With 'H' though 0 indicates a 24-hour time, therefore we disregard the day period. + sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm b")); + assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 00:37 midnight", + k003700, sdf.parse(UnicodeString("2015-11-13 00:37 midnight"), errorCode)); + assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 00:37 noon", + k003700, sdf.parse(UnicodeString("2015-11-13 00:37 noon"), errorCode)); + + // If "midnight" or "noon" is parsed with a 12-hour time other than 12:00, choose + // the version that's closer to the period given. + sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm b")); + assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 03:00 midnight", + k030000, sdf.parse(UnicodeString("2015-11-13 03:00 midnight"), errorCode)); + assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 03:00 noon", + k150000, sdf.parse(UnicodeString("2015-11-13 03:00 noon"), errorCode)); +} #endif /* #if !UCONFIG_NO_FORMATTING */