From e7d56c1f66615faf601d74009a12a6690ea9122f Mon Sep 17 00:00:00 2001 From: =?utf8?q?kaz=C3=A8de=20king?= Date: Sat, 27 Feb 2016 00:41:21 +0000 Subject: [PATCH] ICU-11872 port date time pattern generator char 'C' from Java to C++ X-SVN-Rev: 38397 --- icu4c/source/i18n/dtptngen.cpp | 82 +++++++++++- icu4c/source/i18n/dtptngen_impl.h | 2 + icu4c/source/i18n/unicode/dtptngen.h | 58 ++++---- icu4c/source/test/intltest/dtptngts.cpp | 170 ++++++++++++++---------- icu4c/source/test/intltest/dtptngts.h | 7 +- 5 files changed, 216 insertions(+), 103 deletions(-) diff --git a/icu4c/source/i18n/dtptngen.cpp b/icu4c/source/i18n/dtptngen.cpp index 6a410d461d7..53b33fee3a5 100644 --- a/icu4c/source/i18n/dtptngen.cpp +++ b/icu4c/source/i18n/dtptngen.cpp @@ -396,8 +396,56 @@ DateTimePatternGenerator::initData(const Locale& locale, UErrorCode &status) { addCLDRData(locale, status); setDateTimeFromCalendar(locale, status); setDecimalSymbols(locale, status); + getPreferredHourFormats(locale, status); } // DateTimePatternGenerator::initData +void DateTimePatternGenerator::getPreferredHourFormats(const Locale &locale, UErrorCode &status) { + if (U_FAILURE(status)) { return; } + + const char *localeID = locale.getName(); + char maxLocaleID[ULOC_FULLNAME_CAPACITY]; + uloc_addLikelySubtags(localeID, maxLocaleID, ULOC_FULLNAME_CAPACITY, &status); + if (U_FAILURE(status)) { return; } + Locale maxLocale = Locale(maxLocaleID); + + const char *country = maxLocale.getCountry(); + if (*country == '\0') { country = "001"; } + const char *language = maxLocale.getLanguage(); + + char langCountry[ULOC_FULLNAME_CAPACITY]; + langCountry[0] = '\0'; + strcat(langCountry, language); + strcat(langCountry, "_"); + strcat(langCountry, country); + + UResourceBundle *rb = ures_openDirect(NULL, "supplementalData", &status); // TODO: local pointer + ures_getByKey(rb, "timeData", rb, &status); + UResourceBundle *countryData = ures_getByKey(rb, langCountry, NULL, &status); + if (status == U_MISSING_RESOURCE_ERROR) { + status = U_ZERO_ERROR; + countryData = ures_getByKey(rb, country, NULL, &status); + } + if (status == U_MISSING_RESOURCE_ERROR) { + status = U_ZERO_ERROR; + fAllowedHourFormats[0] = UnicodeString(CAP_H); + fAllowedHourFormatsLength = 1; + return; + } + + ures_getByKey(countryData, "allowed", rb, &status); + if (ures_getType(rb) == URES_STRING) { + fAllowedHourFormats[0] = ures_getUnicodeString(rb, &status); + fAllowedHourFormatsLength = 1; + } else if (ures_getType(rb) == URES_ARRAY) { + fAllowedHourFormatsLength = ures_getSize(rb); + for (int32_t i = 0; i < fAllowedHourFormatsLength; ++i) { + fAllowedHourFormats[i] = ures_getUnicodeStringByIndex(rb, i, &status); + } + } else { + status = U_INVALID_FORMAT_ERROR; + } +} + UnicodeString DateTimePatternGenerator::getSkeleton(const UnicodeString& pattern, UErrorCode& /*status*/) { @@ -539,7 +587,7 @@ DateTimePatternGenerator::addCLDRData(const Locale& locale, UErrorCode& err) { UnicodeString defaultItemFormat(TRUE, UDATPG_ItemFormat, UPRV_LENGTHOF(UDATPG_ItemFormat)-1); // Read-only alias. err = U_ZERO_ERROR; - + fDefaultHourFormatChar = 0; for (i=0; i0) { hackTimes(hackPattern, err); @@ -803,7 +851,7 @@ DateTimePatternGenerator::getBestPattern(const UnicodeString& patternForm, UDate int32_t dateMask=(1< 0) { + preferred = fAllowedHourFormats[0]; + } else { + status = U_INVALID_FORMAT_ERROR; + return UnicodeString(); + } + patternFormCopy.setCharAt(patPos, preferred.charAt(0)); + UChar lastChar = preferred.charAt(preferred.length()-1); + if (lastChar == CAP_B) { + flags |= kDTPGSkeletonUsesCapB; + } else if (lastChar == LOW_B) { + flags |= kDTPGSkeletonUsesLowB; + } } else if (patChr == CAP_J) { // Get pattern for skeleton with H, then replace H or k // with fDefaultHourFormatChar (if different) @@ -1097,6 +1160,19 @@ DateTimePatternGenerator::adjustFieldTypes(const UnicodeString& pattern, } const dtTypeElem *row = &dtTypes[canonicalIndex]; int32_t typeValue = row->field; + + // Handle special day periods. + if (typeValue == UDATPG_DAYPERIOD_FIELD && flags != 0) { + UChar c = NONE; // '0' + if (flags & kDTPGSkeletonUsesCapB) { c = CAP_B; } + if (flags & kDTPGSkeletonUsesLowB) { c = LOW_B; } + + if (c != NONE) { + for (int32_t i = 0; i < field.length(); ++i) + field.setCharAt(i, c); + } + } + if ((flags & kDTPGFixFractionalSeconds) != 0 && typeValue == UDATPG_SECOND_FIELD) { UnicodeString newField=dtMatcher->skeleton.original[UDATPG_FRACTIONAL_SECOND_FIELD]; field = field + decimal + newField; diff --git a/icu4c/source/i18n/dtptngen_impl.h b/icu4c/source/i18n/dtptngen_impl.h index 72cc76a0389..0cfa88ab4d4 100644 --- a/icu4c/source/i18n/dtptngen_impl.h +++ b/icu4c/source/i18n/dtptngen_impl.h @@ -39,6 +39,7 @@ #define DOT ((UChar)0x002E) #define COLON ((UChar)0x003A) #define CAP_A ((UChar)0x0041) +#define CAP_B ((UChar)0x0042) #define CAP_C ((UChar)0x0043) #define CAP_D ((UChar)0x0044) #define CAP_E ((UChar)0x0045) @@ -61,6 +62,7 @@ #define CAP_Z ((UChar)0x005A) #define LOWLINE ((UChar)0x005F) #define LOW_A ((UChar)0x0061) +#define LOW_B ((UChar)0x0062) #define LOW_C ((UChar)0x0063) #define LOW_D ((UChar)0x0064) #define LOW_E ((UChar)0x0065) diff --git a/icu4c/source/i18n/unicode/dtptngen.h b/icu4c/source/i18n/unicode/dtptngen.h index 39d1055a858..ce44e75507a 100644 --- a/icu4c/source/i18n/unicode/dtptngen.h +++ b/icu4c/source/i18n/unicode/dtptngen.h @@ -34,15 +34,15 @@ class PtnSkeleton; class SharedDateTimePatternGenerator; /** - * This class provides flexible generation of date format patterns, like "yy-MM-dd". - * The user can build up the generator by adding successive patterns. Once that + * This class provides flexible generation of date format patterns, like "yy-MM-dd". + * The user can build up the generator by adding successive patterns. Once that * is done, a query can be made using a "skeleton", which is a pattern which just - * includes the desired fields and lengths. The generator will return the "best fit" + * includes the desired fields and lengths. The generator will return the "best fit" * pattern corresponding to that skeleton. *

The main method people will use is getBestPattern(String skeleton), - * since normally this class is pre-built with data from a particular locale. + * since normally this class is pre-built with data from a particular locale. * However, generators can be built directly from other data as well. - *

Issue: may be useful to also have a function that returns the list of + *

Issue: may be useful to also have a function that returns the list of * fields in a pattern, in order, since we have that internally. * That would be useful for getting the UI order of field elements. * @stable ICU 3.8 @@ -84,7 +84,7 @@ public: * @stable ICU 3.8 */ static DateTimePatternGenerator* U_EXPORT2 createEmptyInstance(UErrorCode& status); - + /** * Destructor. * @stable ICU 3.8 @@ -92,7 +92,7 @@ public: virtual ~DateTimePatternGenerator(); /** - * Clone DateTimePatternGenerator object. Clients are responsible for + * Clone DateTimePatternGenerator object. Clients are responsible for * deleting the DateTimePatternGenerator object cloned. * @stable ICU 3.8 */ @@ -106,7 +106,7 @@ public: * @stable ICU 3.8 */ UBool operator==(const DateTimePatternGenerator& other) const; - + /** * Return true if another object is semantically unequal to this one. * @@ -192,19 +192,19 @@ public: * Adds a pattern to the generator. If the pattern has the same skeleton as * an existing pattern, and the override parameter is set, then the previous * value is overriden. Otherwise, the previous value is retained. In either - * case, the conflicting status is set and previous vale is stored in + * case, the conflicting status is set and previous vale is stored in * conflicting pattern. *

* Note that single-field patterns (like "MMM") are automatically added, and * don't need to be added explicitly! * * @param pattern Input pattern, such as "dd/MMM" - * @param override When existing values are to be overridden use true, + * @param override When existing values are to be overridden use true, * otherwise use false. * @param conflictingPattern Previous pattern with the same skeleton. * @param status Output param set to success/failure code on exit, * which must not indicate a failure before the function call. - * @return conflicting status. The value could be UDATPG_NO_CONFLICT, + * @return conflicting status. The value could be UDATPG_NO_CONFLICT, * UDATPG_BASE_CONFLICT or UDATPG_CONFLICT. * @stable ICU 3.8 *

@@ -213,8 +213,8 @@ public: * \snippet samples/dtptngsample/dtptngsample.cpp addPatternExample *

*/ - UDateTimePatternConflict addPattern(const UnicodeString& pattern, - UBool override, + UDateTimePatternConflict addPattern(const UnicodeString& pattern, + UBool override, UnicodeString& conflictingPattern, UErrorCode& status); @@ -367,8 +367,8 @@ public: * \snippet samples/dtptngsample/dtptngsample.cpp replaceFieldTypesExample *

*/ - UnicodeString replaceFieldTypes(const UnicodeString& pattern, - const UnicodeString& skeleton, + UnicodeString replaceFieldTypes(const UnicodeString& pattern, + const UnicodeString& skeleton, UErrorCode& status); /** @@ -393,8 +393,8 @@ public: * @return pattern adjusted to match the skeleton fields widths and subtypes. * @stable ICU 4.4 */ - UnicodeString replaceFieldTypes(const UnicodeString& pattern, - const UnicodeString& skeleton, + UnicodeString replaceFieldTypes(const UnicodeString& pattern, + const UnicodeString& skeleton, UDateTimePatternMatchOptions options, UErrorCode& status); @@ -413,12 +413,12 @@ public: /** * Get the pattern corresponding to a given skeleton. - * @param skeleton + * @param skeleton * @return pattern corresponding to a given skeleton. * @stable ICU 3.8 */ const UnicodeString& getPatternForSkeleton(const UnicodeString& skeleton) const; - + /** * Return a list of all the base skeletons (in canonical form) from this class. * @@ -432,11 +432,11 @@ public: #ifndef U_HIDE_INTERNAL_API /** - * Return a list of redundant patterns are those which if removed, make no - * difference in the resulting getBestPattern values. This method returns a - * list of them, to help check the consistency of the patterns used to build + * Return a list of redundant patterns are those which if removed, make no + * difference in the resulting getBestPattern values. This method returns a + * list of them, to help check the consistency of the patterns used to build * this generator. - * + * * @param status Output param set to success/failure code on exit, * which must not indicate a failure before the function call. * @return a StringEnumeration with the redundant pattern. @@ -454,7 +454,7 @@ public: * the decimal string is ",". Then the resulting pattern is modified to be * "H:mm:ss,SSSS" * - * @param decimal + * @param decimal * @stable ICU 3.8 */ void setDecimal(const UnicodeString& decimal); @@ -521,12 +521,17 @@ private: UnicodeString hackPattern; UnicodeString emptyString; UChar fDefaultHourFormatChar; - + + UnicodeString fAllowedHourFormats[6]; // At most six types of format allowed. + int32_t fAllowedHourFormatsLength; + /* internal flags masks for adjustFieldTypes etc. */ enum { kDTPGNoFlags = 0, kDTPGFixFractionalSeconds = 1, - kDTPGSkeletonUsesCapJ = 2 + kDTPGSkeletonUsesCapJ = 2, + kDTPGSkeletonUsesLowB = 3, + kDTPGSkeletonUsesCapB = 4, }; void initData(const Locale &locale, UErrorCode &status); @@ -550,6 +555,7 @@ private: UBool isAvailableFormatSet(const UnicodeString &key) const; void copyHashtable(Hashtable *other, UErrorCode &status); UBool isCanonicalItem(const UnicodeString& item) const; + void getPreferredHourFormats(const Locale &locale, UErrorCode &status); } ;// end class DateTimePatternGenerator U_NAMESPACE_END diff --git a/icu4c/source/test/intltest/dtptngts.cpp b/icu4c/source/test/intltest/dtptngts.cpp index 7ab972bcef7..f72f10d04de 100644 --- a/icu4c/source/test/intltest/dtptngts.cpp +++ b/icu4c/source/test/intltest/dtptngts.cpp @@ -1,5 +1,5 @@ /******************************************************************** - * COPYRIGHT: + * COPYRIGHT: * Copyright (c) 2008-2016, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ @@ -10,7 +10,7 @@ #include #include -#include "dtptngts.h" +#include "dtptngts.h" #include "unicode/calendar.h" #include "unicode/smpdtfmt.h" @@ -32,11 +32,12 @@ void IntlTestDateTimePatternGeneratorAPI::runIndexedTest( int32_t index, UBool e TESTCASE(1, testOptions); TESTCASE(2, testAllFieldPatterns); TESTCASE(3, testStaticGetSkeleton); + TESTCASE(4, testC); default: name = ""; break; } } -#define MAX_LOCALE 11 +#define MAX_LOCALE 11 /** * Test various generic API methods of DateTimePatternGenerator for API coverage. @@ -63,7 +64,7 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) UnicodeString("JJmm"), // 16 UnicodeString(), }; - + const char* testLocale[MAX_LOCALE][4] = { {"en", "US", "", ""}, // 0 {"en", "US", "", "calendar=japanese"}, // 1 @@ -77,7 +78,7 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) {"ru", "", "", ""}, // 9 {"zh", "", "", "calendar=chinese"}, // 10 }; - + // For Weds, Jan 13, 1999, 23:58:59 UnicodeString patternResults[] = { // en_US // 0 en_US @@ -232,7 +233,7 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) CharsToUnicodeString("\\u4E0B\\u534811:58:59.123"), // 15: jmmssSSS -> "ah:mm:ss.SSS" UnicodeString("11:58"), // 16: JJmm - // zh_TW@calendar=roc // 8 zh_TW@calendar=roc + // zh_TW@calendar=roc // 8 zh_TW@calendar=roc CharsToUnicodeString("\\u6C11\\u570B88/1"), // 00: yM -> Gy/M CharsToUnicodeString("\\u6C11\\u570B88\\u5E741\\u6708"), // 01: yMMM -> Gy\u5E74M\u6708 CharsToUnicodeString("\\u6C11\\u570B88/1/13"), // 02: yMd -> Gy/M/d @@ -338,17 +339,17 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) UnicodeString("6:58 AM GMT"), UnicodeString(""), }; - + // results for getSkeletons() and getPatternForSkeleton() - const UnicodeString testSkeletonsResults[] = { - UnicodeString("HH:mm"), - UnicodeString("MMMMd"), - UnicodeString("MMMMMdd"), + const UnicodeString testSkeletonsResults[] = { + UnicodeString("HH:mm"), + UnicodeString("MMMMd"), + UnicodeString("MMMMMdd"), }; - - const UnicodeString testBaseSkeletonsResults[] = { - UnicodeString("Hm"), - UnicodeString("MMMMd"), + + const UnicodeString testBaseSkeletonsResults[] = { + UnicodeString("Hm"), + UnicodeString("MMMMd"), UnicodeString("MMMMMd"), }; @@ -363,7 +364,7 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) // ======= Test CreateInstance with default locale logln("Testing DateTimePatternGenerator createInstance from default locale"); - + DateTimePatternGenerator *instFromDefaultLocale=DateTimePatternGenerator::createInstance(status); if (U_FAILURE(status)) { dataerrln("ERROR: Could not create DateTimePatternGenerator (default) - exitting"); @@ -373,7 +374,7 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) delete instFromDefaultLocale; } - // ======= Test CreateInstance with given locale + // ======= Test CreateInstance with given locale logln("Testing DateTimePatternGenerator createInstance from French locale"); status = U_ZERO_ERROR; DateTimePatternGenerator *instFromLocale=DateTimePatternGenerator::createInstance(Locale::getFrench(), status); @@ -382,10 +383,10 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) return; } - // ======= Test clone DateTimePatternGenerator + // ======= Test clone DateTimePatternGenerator logln("Testing DateTimePatternGenerator::clone()"); status = U_ZERO_ERROR; - + UnicodeString decimalSymbol = instFromLocale->getDecimal(); UnicodeString newDecimalSymbol = UnicodeString("*"); @@ -399,15 +400,15 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) if ( !(*cloneDTPatternGen == *instFromLocale) ) { errln("ERROR: inconsistency is found in cloned object."); } - + if ( *cloneDTPatternGen != *instFromLocale ) { errln("ERROR: inconsistency is found in cloned object."); } - + delete instFromLocale; delete cloneDTPatternGen; - - // ======= Test simple use cases + + // ======= Test simple use cases logln("Testing simple use cases"); status = U_ZERO_ERROR; Locale deLocale=Locale::getGermany(); @@ -441,7 +442,7 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) } // add new pattern status = U_ZERO_ERROR; - conflictingStatus = gen->addPattern(UnicodeString("d'. von' MMMM", -1, US_INV), true, conflictingPattern, status); + conflictingStatus = gen->addPattern(UnicodeString("d'. von' MMMM", -1, US_INV), true, conflictingPattern, status); if (U_FAILURE(status)) { errln("ERROR: Could not addPattern - d\'. von\' MMMM"); } @@ -456,9 +457,9 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) errln(UnicodeString("ERROR: Simple test addPattern failed!: d\'. von\' MMMM Got: ") + dateReturned + UnicodeString(" Expected: ") + expectedResult); } delete format; - + // get a pattern and modify it - format = (SimpleDateFormat *)DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, + format = (SimpleDateFormat *)DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, deLocale); format->setTimeZone(*zone); UnicodeString pattern; @@ -470,8 +471,8 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) errln("ERROR: Simple test uses full date format."); errln(UnicodeString(" Got: ") + dateReturned + UnicodeString(" Expected: ") + expectedResult); } - - // modify it to change the zone. + + // modify it to change the zone. UnicodeString newPattern = gen->replaceFieldTypes(pattern, UnicodeString("vvvv"), status); format->applyPattern(newPattern); dateReturned.remove(); @@ -481,31 +482,31 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) errln("ERROR: Simple test modify the timezone!"); errln(UnicodeString(" Got: ")+ dateReturned + UnicodeString(" Expected: ") + expectedResult); } - + // setDeciaml(), getDeciaml() gen->setDecimal(newDecimal); if (newDecimal != gen->getDecimal()) { errln("ERROR: unexpected result from setDecimal() and getDecimal()!.\n"); } - + // setAppenItemName() , getAppendItemName() gen->setAppendItemName(UDATPG_HOUR_FIELD, newAppendItemName); if (newAppendItemName != gen->getAppendItemName(UDATPG_HOUR_FIELD)) { errln("ERROR: unexpected result from setAppendItemName() and getAppendItemName()!.\n"); } - + // setAppenItemFormat() , getAppendItemFormat() gen->setAppendItemFormat(UDATPG_HOUR_FIELD, newAppendItemFormat); if (newAppendItemFormat != gen->getAppendItemFormat(UDATPG_HOUR_FIELD)) { errln("ERROR: unexpected result from setAppendItemFormat() and getAppendItemFormat()!.\n"); } - + // setDateTimeFormat() , getDateTimeFormat() gen->setDateTimeFormat(newDateTimeFormat); if (newDateTimeFormat != gen->getDateTimeFormat()) { errln("ERROR: unexpected result from setDateTimeFormat() and getDateTimeFormat()!.\n"); } - + // ======== Test getSkeleton and getBaseSkeleton status = U_ZERO_ERROR; pattern = UnicodeString("dd-MMM"); @@ -538,7 +539,7 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) delete format; delete zone; delete gen; - + { // Trac# 6104 status = U_ZERO_ERROR; @@ -561,10 +562,10 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) logln(UnicodeString(" Formatted date:") + rDate); if ( expR!= rDate ) { - errln(UnicodeString("\nERROR: Test Japanese month hack Got: ") + rDate + + errln(UnicodeString("\nERROR: Test Japanese month hack Got: ") + rDate + UnicodeString(" Expected: ") + expR ); } - + delete patGen; } { // Trac# 6104 @@ -585,10 +586,10 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) logln(UnicodeString(" zh locale with skeleton: YYYYMMM Best Pattern:") + bPattern); logln(UnicodeString(" Formatted date:") + rDate); if ( expR!= rDate ) { - errln(UnicodeString("\nERROR: Test Chinese month hack Got: ") + rDate + + errln(UnicodeString("\nERROR: Test Chinese month hack Got: ") + rDate + UnicodeString(" Expected: ") + expR ); } - delete patGen; + delete patGen; } { @@ -606,27 +607,27 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) logln(UnicodeString(" en locale with skeleton: hmv Best Pattern:") + bPattern); if ( expR!= bPattern ) { - errln(UnicodeString("\nERROR: Test EN time format Got: ") + bPattern + + errln(UnicodeString("\nERROR: Test EN time format Got: ") + bPattern + UnicodeString(" Expected: ") + expR ); } - + delete patGen; } - - + + // ======= Test various skeletons. logln("Testing DateTimePatternGenerator with various skeleton"); - + status = U_ZERO_ERROR; int32_t localeIndex=0; int32_t resultIndex=0; UnicodeString resultDate; UDate testDate= LocaleTest::date(99, 0, 13, 23, 58, 59) + 123.0; while (localeIndex < MAX_LOCALE ) - { + { int32_t dataIndex=0; UnicodeString bestPattern; - + Locale loc(testLocale[localeIndex][0], testLocale[localeIndex][1], testLocale[localeIndex][2], testLocale[localeIndex][3]); logln("\n\n Locale: %s_%s_%s@%s", testLocale[localeIndex][0], testLocale[localeIndex][1], testLocale[localeIndex][2], testLocale[localeIndex][3]); DateTimePatternGenerator *patGen=DateTimePatternGenerator::createInstance(loc, status); @@ -638,7 +639,7 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) log(patternData[dataIndex]); bestPattern = patGen->getBestPattern(patternData[dataIndex++], status); logln(UnicodeString(" -> ") + bestPattern); - + SimpleDateFormat sdf(bestPattern, loc, status); resultDate.remove(); resultDate = sdf.format(testDate, resultDate); @@ -646,21 +647,21 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) errln(UnicodeString("\nERROR: Test various skeletons[") + (dataIndex-1) + UnicodeString("], localeIndex ") + localeIndex + UnicodeString(". Got: \"") + resultDate + UnicodeString("\" Expected: \"") + patternResults[resultIndex] + "\"" ); } - + resultIndex++; } delete patGen; localeIndex++; } - + // ======= More tests ticket#6110 logln("Testing DateTimePatternGenerator with various skeleton"); - + status = U_ZERO_ERROR; localeIndex=0; resultIndex=0; testDate= LocaleTest::date(99, 9, 13, 23, 58, 59); - { + { int32_t dataIndex=0; UnicodeString bestPattern; logln("\n\n Test various skeletons for English locale..."); @@ -675,7 +676,7 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) delete patGen; return; } - SimpleDateFormat *enFormat = (SimpleDateFormat *)DateFormat::createDateTimeInstance(DateFormat::kFull, + SimpleDateFormat *enFormat = (SimpleDateFormat *)DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale::getEnglish()); enFormat->setTimeZone(*enZone); while (patternTests2[dataIndex].length() > 0) { @@ -687,7 +688,7 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) resultDate = enFormat->format(testDate, resultDate); if ( resultDate != patternResults2[resultIndex] ) { errln(UnicodeString("\nERROR: Test various skeletons[") + dataIndex - + UnicodeString("]. Got: ") + resultDate + UnicodeString(" Expected: ") + + + UnicodeString("]. Got: ") + resultDate + UnicodeString(" Expected: ") + patternResults2[resultIndex] ); } dataIndex++; @@ -700,7 +701,7 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) - // ======= Test random skeleton + // ======= Test random skeleton DateTimePatternGenerator *randDTGen= DateTimePatternGenerator::createInstance(status); if (U_FAILURE(status)) { dataerrln("ERROR: Could not create DateTimePatternGenerator (Locale::getFrench()) - exitting"); @@ -719,35 +720,35 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) UnicodeString bestPattern = randDTGen->getBestPattern(randomSkeleton, status); } delete randDTGen; - + // UnicodeString randomString=Unicode // ======= Test getStaticClassID() logln("Testing getStaticClassID()"); status = U_ZERO_ERROR; DateTimePatternGenerator *test= DateTimePatternGenerator::createInstance(status); - + if(test->getDynamicClassID() != DateTimePatternGenerator::getStaticClassID()) { errln("ERROR: getDynamicClassID() didn't return the expected value"); } delete test; - + // ====== Test createEmptyInstance() - + logln("Testing createEmptyInstance()"); status = U_ZERO_ERROR; - + test = DateTimePatternGenerator::createEmptyInstance(status); if(U_FAILURE(status)) { errln("ERROR: Fail to create an empty instance ! - exitting.\n"); delete test; return; } - - conflictingStatus = test->addPattern(UnicodeString("MMMMd"), true, conflictingPattern, status); + + conflictingStatus = test->addPattern(UnicodeString("MMMMd"), true, conflictingPattern, status); status = U_ZERO_ERROR; testPattern=test->getBestPattern(UnicodeString("MMMMdd"), status); - conflictingStatus = test->addPattern(UnicodeString("HH:mm"), true, conflictingPattern, status); + conflictingStatus = test->addPattern(UnicodeString("HH:mm"), true, conflictingPattern, status); conflictingStatus = test->addPattern(UnicodeString("MMMMMdd"), true, conflictingPattern, status); //duplicate pattern StringEnumeration *output=NULL; output = test->getRedundants(status); @@ -759,7 +760,7 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) errln("ERROR: Fail in getRedundants !\n"); } } - + // ======== Test getSkeletons and getBaseSkeletons StringEnumeration* ptrSkeletonEnum = test->getSkeletons(status); if(U_FAILURE(status)) { @@ -780,7 +781,7 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) StringEnumeration* ptrBaseSkeletonEnum = test->getBaseSkeletons(status); if(U_FAILURE(status)) { errln("ERROR: Fail to get base skeletons !\n"); - } + } count=ptrBaseSkeletonEnum->count(status); for (i=0; isnext(status); @@ -794,16 +795,16 @@ void IntlTestDateTimePatternGeneratorAPI::testAPI(/*char *par*/) Locale locale = Locale::getFrench(); status = U_ZERO_ERROR; DateTimePatternGenerator *generator = DateTimePatternGenerator::createInstance( locale, status); - + // get a pattern for an abbreviated month and day - pattern = generator->getBestPattern(UnicodeString("MMMd"), status); - SimpleDateFormat formatter(pattern, locale, status); + pattern = generator->getBestPattern(UnicodeString("MMMd"), status); + SimpleDateFormat formatter(pattern, locale, status); zone = TimeZone::createTimeZone(UnicodeString("GMT")); formatter.setTimeZone(*zone); // use it to format (or parse) UnicodeString formatted; - formatted = formatter.format(Calendar::getNow(), formatted, status); + formatted = formatter.format(Calendar::getNow(), formatted, status); // for French, the result is "13 sept." formatted.remove(); // cannot use the result from getNow() because the value change evreyday. @@ -888,10 +889,10 @@ void IntlTestDateTimePatternGeneratorAPI::testOptions(/*char *par*/) { "zh@calendar=chinese", "yMMM", "rU\\u5E74MMM", UDATPG_MATCH_NO_OPTIONS }, { "zh@calendar=chinese", "GUMMM", "rU\\u5E74MMM", UDATPG_MATCH_NO_OPTIONS }, }; - + int count = UPRV_LENGTHOF(testData); const DTPtnGenOptionsData * testDataPtr = testData; - + for (; count-- > 0; ++testDataPtr) { UErrorCode status = U_ZERO_ERROR; @@ -995,7 +996,7 @@ void IntlTestDateTimePatternGeneratorAPI::testAllFieldPatterns(/*char *par*/) { 'X', {1,2,3,4,5,0}, "X" }, // x { 'x', {1,2,3,4,5,0}, "x" }, // x }; - + const char ** localeNamesPtr = localeNames; const char * localeName; while ( (localeName = *localeNamesPtr++) != NULL) { @@ -1048,7 +1049,7 @@ void IntlTestDateTimePatternGeneratorAPI::testAllFieldPatterns(/*char *par*/) ", skeleton " + skeleton + ", produces pattern without required chars: " + pattern); } - + } } } @@ -1079,4 +1080,31 @@ void IntlTestDateTimePatternGeneratorAPI::testStaticGetSkeleton(/*char *par*/) assertEquals("Skeleton", testData[i], skeleton); } } + +void IntlTestDateTimePatternGeneratorAPI::testC() { + UErrorCode status = U_ZERO_ERROR; + const int32_t numLocales = 6; + + const char* tests[numLocales][3] = { + {"zh", "Cm", "Bh:mm"}, + {"de", "Cm", "HH:mm"}, + {"en", "Cm", "h:mm a"}, + {"en-BN", "Cm", "h:mm b"}, + {"gu-IN", "Cm", "h:mm B"}, + {"und-IN", "Cm", "h:mm a"}, + }; + + for (int32_t i = 0; i < numLocales; ++i) { + DateTimePatternGenerator *gen = DateTimePatternGenerator::createInstance(Locale(tests[i][0]), status); + UnicodeString pattern = gen->getBestPattern(tests[i][1], status); + UnicodeString expectedPattern = tests[i][2]; + + char message[100] = "\0"; + strcat(message, tests[i][0]); + strcat(message, "/"); + strcat(message, tests[i][1]); + assertEquals(message, expectedPattern, pattern); + } +} + #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/test/intltest/dtptngts.h b/icu4c/source/test/intltest/dtptngts.h index dd368457ba1..8793987d465 100644 --- a/icu4c/source/test/intltest/dtptngts.h +++ b/icu4c/source/test/intltest/dtptngts.h @@ -1,6 +1,6 @@ /******************************************************************** - * COPYRIGHT: - * Copyright (c) 1997-2001,2009,2013,2015 International Business Machines Corporation and + * COPYRIGHT: + * Copyright (c) 1997-2016 International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ @@ -17,7 +17,7 @@ * Test basic functionality of various API functions **/ class IntlTestDateTimePatternGeneratorAPI : public IntlTest { - void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL ); + void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL ); private: /** @@ -27,6 +27,7 @@ private: void testOptions(/* char* par */); void testAllFieldPatterns(/* char* par */); void testStaticGetSkeleton(/* char* par */); + void testC(); }; #endif /* #if !UCONFIG_NO_FORMATTING */ -- 2.40.0