diff --git a/icu4c/source/i18n/dtfmtsym.cpp b/icu4c/source/i18n/dtfmtsym.cpp index 3cc7ceb1465..61755b05ca9 100644 --- a/icu4c/source/i18n/dtfmtsym.cpp +++ b/icu4c/source/i18n/dtfmtsym.cpp @@ -177,7 +177,6 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateFormatSymbols) * with a locale and calendar */ static const char gErasTag[]="eras"; -static const char gAbbreviatedTag[] = "abbreviated"; static const char gMonthNamesTag[]="monthNames"; static const char gDayNamesTag[]="dayNames"; static const char gNamesWideTag[]="wide"; @@ -310,6 +309,7 @@ void DateFormatSymbols::copyData(const DateFormatSymbols& other) { assignArray(fEras, fErasCount, other.fEras, other.fErasCount); assignArray(fEraNames, fEraNamesCount, other.fEraNames, other.fEraNamesCount); + assignArray(fNarrowEras, fNarrowErasCount, other.fNarrowEras, other.fNarrowErasCount); assignArray(fMonths, fMonthsCount, other.fMonths, other.fMonthsCount); assignArray(fShortMonths, fShortMonthsCount, other.fShortMonths, other.fShortMonthsCount); assignArray(fNarrowMonths, fNarrowMonthsCount, other.fNarrowMonths, other.fNarrowMonthsCount); @@ -371,6 +371,7 @@ void DateFormatSymbols::dispose() { if (fEras) delete[] fEras; if (fEraNames) delete[] fEraNames; + if (fNarrowEras) delete[] fNarrowEras; if (fMonths) delete[] fMonths; if (fShortMonths) delete[] fShortMonths; if (fNarrowMonths) delete[] fNarrowMonths; @@ -447,6 +448,7 @@ DateFormatSymbols::operator==(const DateFormatSymbols& other) const } if (fErasCount == other.fErasCount && fEraNamesCount == other.fEraNamesCount && + fNarrowErasCount == other.fNarrowErasCount && fMonthsCount == other.fMonthsCount && fShortMonthsCount == other.fShortMonthsCount && fNarrowMonthsCount == other.fNarrowMonthsCount && @@ -470,6 +472,7 @@ DateFormatSymbols::operator==(const DateFormatSymbols& other) const // Now compare the arrays themselves if (arrayCompare(fEras, other.fEras, fErasCount) && arrayCompare(fEraNames, other.fEraNames, fEraNamesCount) && + arrayCompare(fNarrowEras, other.fNarrowEras, fNarrowErasCount) && arrayCompare(fMonths, other.fMonths, fMonthsCount) && arrayCompare(fShortMonths, other.fShortMonths, fShortMonthsCount) && arrayCompare(fNarrowMonths, other.fNarrowMonths, fNarrowMonthsCount) && @@ -526,6 +529,13 @@ DateFormatSymbols::getEraNames(int32_t &count) const return fEraNames; } +const UnicodeString* +DateFormatSymbols::getNarrowEras(int32_t &count) const +{ + count = fNarrowErasCount; + return fNarrowEras; +} + const UnicodeString* DateFormatSymbols::getMonths(int32_t &count) const { @@ -734,6 +744,20 @@ DateFormatSymbols::setEraNames(const UnicodeString* eraNamesArray, int32_t count fEraNamesCount = count; } +void +DateFormatSymbols::setNarrowEras(const UnicodeString* narrowErasArray, int32_t count) +{ + // delete the old list if we own it + if (fNarrowEras) + delete[] fNarrowEras; + + // we always own the new list, which we create here (we duplicate rather + // than adopting the list passed in) + fNarrowEras = newUnicodeStringArray(count); + uprv_arrayCopy(narrowErasArray,fNarrowEras, count); + fNarrowErasCount = count; +} + void DateFormatSymbols::setMonths(const UnicodeString* monthsArray, int32_t count) { @@ -1167,6 +1191,8 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError fErasCount = 0; fEraNames = NULL; fEraNamesCount = 0; + fNarrowEras = NULL; + fNarrowErasCount = 0; fMonths = NULL; fMonthsCount=0; fShortMonths = NULL; @@ -1235,12 +1261,19 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError // load the first data item UResourceBundle *erasMain = calData.getByKey(gErasTag, status); - UResourceBundle *eras = ures_getByKeyWithFallback(erasMain, gAbbreviatedTag, NULL, &status); + UResourceBundle *eras = ures_getByKeyWithFallback(erasMain, gNamesAbbrTag, NULL, &status); UErrorCode oldStatus = status; UResourceBundle *eraNames = ures_getByKeyWithFallback(erasMain, gNamesWideTag, NULL, &status); if ( status == U_MISSING_RESOURCE_ERROR ) { // Workaround because eras/wide was omitted from CLDR 1.3 status = oldStatus; - eraNames = ures_getByKeyWithFallback(erasMain, gAbbreviatedTag, NULL, &status); + eraNames = ures_getByKeyWithFallback(erasMain, gNamesAbbrTag, NULL, &status); + } + // current ICU4J falls back to abbreviated if narrow eras are missing, so we will too + oldStatus = status; + UResourceBundle *narrowEras = ures_getByKeyWithFallback(erasMain, gNamesNarrowTag, NULL, &status); + if ( status == U_MISSING_RESOURCE_ERROR ) { + status = oldStatus; + narrowEras = ures_getByKeyWithFallback(erasMain, gNamesAbbrTag, NULL, &status); } UResourceBundle *lsweekdaysData = NULL; // Data closed by calData @@ -1264,6 +1297,7 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError initField(&fEras, fErasCount, (const UChar *)gLastResortEras, kEraNum, kEraLen, status); initField(&fEraNames, fEraNamesCount, (const UChar *)gLastResortEras, kEraNum, kEraLen, status); + initField(&fNarrowEras, fNarrowErasCount, (const UChar *)gLastResortEras, kEraNum, kEraLen, status); initField(&fMonths, fMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status); initField(&fShortMonths, fShortMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status); initField(&fNarrowMonths, fNarrowMonthsCount, (const UChar *)gLastResortMonthNames, kMonthNum, kMonthLen, status); @@ -1296,6 +1330,7 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError initField(&fEras, fErasCount, eras, status); initField(&fEraNames, fEraNamesCount, eraNames, status); + initField(&fNarrowEras, fNarrowErasCount, narrowEras, status); initField(&fMonths, fMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesWideTag, status), status); initField(&fShortMonths, fShortMonthsCount, calData.getByKey2(gMonthNamesTag, gNamesAbbrTag, status), status); @@ -1521,6 +1556,7 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError cleanup: ures_close(eras); ures_close(eraNames); + ures_close(narrowEras); ures_close(zoneStringsArray); ures_close(localeBundle); } diff --git a/icu4c/source/i18n/smpdtfmt.cpp b/icu4c/source/i18n/smpdtfmt.cpp index f20d7694958..1d5da91ed78 100644 --- a/icu4c/source/i18n/smpdtfmt.cpp +++ b/icu4c/source/i18n/smpdtfmt.cpp @@ -1046,9 +1046,11 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo, switch (patternCharIndex) { // for any "G" symbol, write out the appropriate era string - // "GGGG" is wide era name, anything else is abbreviated name + // "GGGG" is wide era name, "GGGGG" is narrow era name, anything else is abbreviated name case UDAT_ERA_FIELD: - if (count >= 4) + if (count == 5) + _appendSymbol(appendTo, value, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount); + else if (count == 4) _appendSymbol(appendTo, value, fSymbols->fEraNames, fSymbols->fEraNamesCount); else _appendSymbol(appendTo, value, fSymbols->fEras, fSymbols->fErasCount); @@ -1925,6 +1927,9 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC switch (patternCharIndex) { case UDAT_ERA_FIELD: + if (count == 5) { + return matchString(text, start, UCAL_ERA, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount, cal); + } if (count == 4) { return matchString(text, start, UCAL_ERA, fSymbols->fEraNames, fSymbols->fEraNamesCount, cal); } diff --git a/icu4c/source/i18n/unicode/dtfmtsym.h b/icu4c/source/i18n/unicode/dtfmtsym.h index 5bc73fef829..a4b08bc3bd1 100644 --- a/icu4c/source/i18n/unicode/dtfmtsym.h +++ b/icu4c/source/i18n/unicode/dtfmtsym.h @@ -1,6 +1,6 @@ /* ******************************************************************************** -* Copyright (C) 1997-2007, International Business Machines +* Copyright (C) 1997-2008, International Business Machines * Corporation and others. All Rights Reserved. ******************************************************************************** * @@ -180,7 +180,7 @@ public: UBool operator!=(const DateFormatSymbols& other) const { return !operator==(other); } /** - * Gets era strings. For example: "AD" and "BC". + * Gets abbreviated era strings. For example: "AD" and "BC". * * @param count Filled in with length of the array. * @return the era strings. @@ -189,7 +189,7 @@ public: const UnicodeString* getEras(int32_t& count) const; /** - * Sets era strings. For example: "AD" and "BC". + * Sets abbreviated era strings. For example: "AD" and "BC". * @param eras Array of era strings (DateFormatSymbols retains ownership.) * @param count Filled in with length of the array. * @stable ICU 2.0 @@ -213,6 +213,23 @@ public: */ void setEraNames(const UnicodeString* eraNames, int32_t count); + /** + * Gets narrow era strings. For example: A" and "D". + * + * @param count Filled in with length of the array. + * @return the narrow era strings. + * @draft ICU 4.2 + */ + const UnicodeString* getNarrowEras(int32_t& count) const; + + /** + * Sets narrow era strings. For example: "A" and "B". + * @param narrowEras Array of narrow era strings (DateFormatSymbols retains ownership.) + * @param count Filled in with length of the array. + * @draft ICU 4.2 + */ + void setNarrowEras(const UnicodeString* narrowEras, int32_t count); + /** * Gets month strings. For example: "January", "February", etc. * @param count Filled in with length of the array. @@ -453,7 +470,7 @@ private: friend class DateFormatSymbolsSingleSetter; // see udat.cpp /** - * Era strings. For example: "AD" and "BC". + * Abbreviated era strings. For example: "AD" and "BC". */ UnicodeString* fEras; int32_t fErasCount; @@ -464,6 +481,12 @@ private: UnicodeString* fEraNames; int32_t fEraNamesCount; + /** + * Narrow era strings. For example: "A" and "B". + */ + UnicodeString* fNarrowEras; + int32_t fNarrowErasCount; + /** * Month strings. For example: "January", "February", etc. */ diff --git a/icu4c/source/test/cintltst/cdtrgtst.c b/icu4c/source/test/cintltst/cdtrgtst.c index e5eecfbda7e..5c649fd8b16 100644 --- a/icu4c/source/test/cintltst/cdtrgtst.c +++ b/icu4c/source/test/cintltst/cdtrgtst.c @@ -39,7 +39,8 @@ void addDateForRgrTest(TestNode** root) addTest(root, &Test4061287, "tsformat/cdtrgtst/Test4061287"); addTest(root, &Test4073003, "tsformat/cdtrgtst/Test4073003"); addTest(root, &Test4162071, "tsformat/cdtrgtst/Test4162071"); - addTest(root, &Test714, "tsformat/cdtrgtst/Test714"); + addTest(root, &Test714, "tsformat/cdtrgtst/Test714"); + addTest(root, &TestJ6072, "tsformat/cdtrgtst/TestJ6072"); } /** @@ -499,6 +500,61 @@ void Test714(void) ctest_resetTimeZone(); } +static const UDate july022008 = 1.215e+12; /* 02 July 2008 5:00 AM PDT (approx ICU 4.0 release date :-) */ +static const UChar zonePST[] = { 'P','S','T',0 }; +static const UChar dmyGGGPattern[] = { 'd','d',' ','M','M','M',' ','y','y','y','y',' ','G','G','G',0 }; +static const UChar dmyGGGGGPattern[] = { 'd','d',' ','M','M','M',' ','y','y','y','y',' ','G','G','G','G','G',0 }; +static const UChar dmyGGGText[] = { '0','2',' ','J','u','l',' ','2','0','0','8',' ','A','D',0 }; +static const UChar dmyGGGGGText[] = { '0','2',' ','J','u','l',' ','2','0','0','8',' ','A',0 }; +static const double dayMillisec = 8.64e+07; +enum { kdmyGnTextMaxChars = 64 }; +void TestJ6072(void) +{ + UErrorCode status = U_ZERO_ERROR; + UDateFormat * dtfmt = udat_open(UDAT_LONG, UDAT_LONG, "en", zonePST, -1, NULL, 0, &status); + if ( U_SUCCESS(status) ) { + UChar dmyGnText[kdmyGnTextMaxChars]; + int32_t dmyGnTextLen; + UDate dateResult; + + udat_applyPattern(dtfmt, FALSE, dmyGGGPattern, -1); + dmyGnTextLen = udat_format(dtfmt, july022008, dmyGnText, kdmyGnTextMaxChars, NULL, &status); + if ( U_FAILURE(status) ) { + log_err("FAIL: udat_format with GGG: %s\n", myErrorName(status) ); + status = U_ZERO_ERROR; + } else if ( u_strcmp(dmyGnText, dmyGGGText) != 0 ) { + log_err("FAIL: udat_format with GGG: wrong UChar[] result\n" ); + } + dateResult = udat_parse(dtfmt, dmyGGGText, -1, NULL, &status); /* no time, dateResult != july022008 by some hours */ + if ( U_FAILURE(status) ) { + log_err("FAIL: udat_parse with GGG: %s\n", myErrorName(status) ); + status = U_ZERO_ERROR; + } else if ( july022008 - dateResult > dayMillisec ) { + log_err("FAIL: udat_parse with GGG: wrong UDate result\n" ); + } + + udat_applyPattern(dtfmt, FALSE, dmyGGGGGPattern, -1); + dmyGnTextLen = udat_format(dtfmt, july022008, dmyGnText, kdmyGnTextMaxChars, NULL, &status); + if ( U_FAILURE(status) ) { + log_err("FAIL: udat_format with GGGGG: %s\n", myErrorName(status) ); + status = U_ZERO_ERROR; + } else if ( u_strcmp(dmyGnText, dmyGGGGGText) != 0 ) { + log_err("FAIL: udat_format with GGGGG: wrong UChar[] result\n" ); + } + dateResult = udat_parse(dtfmt, dmyGGGGGText, -1, NULL, &status); /* no time, dateResult != july022008 by some hours */ + if ( U_FAILURE(status) ) { + log_err("FAIL: udat_parse with GGGGG: %s\n", myErrorName(status) ); + status = U_ZERO_ERROR; + } else if ( july022008 - dateResult > dayMillisec ) { + log_err("FAIL: udat_parse with GGGGG: wrong UDate result\n" ); + } + + udat_close(dtfmt); + } else { + log_err("FAIL: udat_open fails: %s\n", myErrorName(status)); + } +} + /*INTERNAL FUNCTION USED */ UChar* myFormatit(UDateFormat* datdef, UDate d1) diff --git a/icu4c/source/test/cintltst/cdtrgtst.h b/icu4c/source/test/cintltst/cdtrgtst.h index 18df92e5ed2..b60b4178a76 100644 --- a/icu4c/source/test/cintltst/cdtrgtst.h +++ b/icu4c/source/test/cintltst/cdtrgtst.h @@ -1,6 +1,6 @@ /******************************************************************** * COPYRIGHT: - * Copyright (c) 1997-2001, International Business Machines Corporation and + * Copyright (c) 1997-2002,2008, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ /******************************************************************************** @@ -23,7 +23,7 @@ #include "cintltst.h" /** - * DateFormat Regresstion tests + * DateFormat Regression tests **/ void Test4029195(void); @@ -34,6 +34,7 @@ void Test4073003(void); void Test4162071(void); void Test714(void); + void TestJ6072(void); /** * test subroutine diff --git a/icu4c/source/test/intltest/tsdtfmsy.cpp b/icu4c/source/test/intltest/tsdtfmsy.cpp index 3aae499398e..663fb6a6bdb 100644 --- a/icu4c/source/test/intltest/tsdtfmsy.cpp +++ b/icu4c/source/test/intltest/tsdtfmsy.cpp @@ -1,5 +1,5 @@ /******************************************************************** - * Copyright (c) 1997-2007, International Business Machines + * Copyright (c) 1997-2008, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************/ @@ -159,9 +159,25 @@ void IntlTestDateFormatSymbols::TestSymbols(/* char *par */) int32_t count = 0; const UnicodeString *eras = en.getEras(count); if(count == 0) { - errln("ERROR: 0 english eras.. exitting..\n"); + errln("ERROR: 0 english eras.. exiting..\n"); return; } + int32_t eraNamesCount = 0; + const UnicodeString *eraNames = en.getEraNames(eraNamesCount); + if(eraNamesCount == 0) { + errln("ERROR: 0 english eraNames\n"); + } else if ( eraNames[0].length() <= eras[0].length() ) { + // At least for English we know a wide eraName should be longer than an abbrev era + errln("ERROR: english eraNames[0] not longer than eras[0]\n"); + } + int32_t narrowErasCount = 0; + const UnicodeString *narrowEras = en.getNarrowEras(narrowErasCount); + if(narrowErasCount == 0) { + errln("ERROR: 0 english narrowEras\n"); + } else if ( narrowEras[0].length() >= eras[0].length() ) { + // At least for English we know a narrowEra should be shorter than an abbrev era + errln("ERROR: english narrowEras[0] not shorter than eras[0]\n"); + } fr.setEras(eras, count); if( *en.getEras(count) != *fr.getEras(count)) {