ICU-21647 Added support for narrow quarter names to DateFormatSymbols and SimpleDateFormat.

This commit is contained in:
Rich Gillam 2021-07-07 17:03:03 -07:00
parent 9ff39368b2
commit dcfdaca46c
12 changed files with 327 additions and 48 deletions

View file

@ -392,8 +392,10 @@ DateFormatSymbols::copyData(const DateFormatSymbols& other) {
fTimeSeparator.fastCopyFrom(other.fTimeSeparator); // fastCopyFrom() - see assignArray comments
assignArray(fQuarters, fQuartersCount, other.fQuarters, other.fQuartersCount);
assignArray(fShortQuarters, fShortQuartersCount, other.fShortQuarters, other.fShortQuartersCount);
assignArray(fNarrowQuarters, fNarrowQuartersCount, other.fNarrowQuarters, other.fNarrowQuartersCount);
assignArray(fStandaloneQuarters, fStandaloneQuartersCount, other.fStandaloneQuarters, other.fStandaloneQuartersCount);
assignArray(fStandaloneShortQuarters, fStandaloneShortQuartersCount, other.fStandaloneShortQuarters, other.fStandaloneShortQuartersCount);
assignArray(fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount, other.fStandaloneNarrowQuarters, other.fStandaloneNarrowQuartersCount);
assignArray(fWideDayPeriods, fWideDayPeriodsCount,
other.fWideDayPeriods, other.fWideDayPeriodsCount);
assignArray(fNarrowDayPeriods, fNarrowDayPeriodsCount,
@ -485,8 +487,10 @@ void DateFormatSymbols::dispose()
delete[] fNarrowAmPms;
delete[] fQuarters;
delete[] fShortQuarters;
delete[] fNarrowQuarters;
delete[] fStandaloneQuarters;
delete[] fStandaloneShortQuarters;
delete[] fStandaloneNarrowQuarters;
delete[] fLeapMonthPatterns;
delete[] fShortYearNames;
delete[] fShortZodiacNames;
@ -563,8 +567,10 @@ DateFormatSymbols::operator==(const DateFormatSymbols& other) const
fNarrowAmPmsCount == other.fNarrowAmPmsCount &&
fQuartersCount == other.fQuartersCount &&
fShortQuartersCount == other.fShortQuartersCount &&
fNarrowQuartersCount == other.fNarrowQuartersCount &&
fStandaloneQuartersCount == other.fStandaloneQuartersCount &&
fStandaloneShortQuartersCount == other.fStandaloneShortQuartersCount &&
fStandaloneNarrowQuartersCount == other.fStandaloneNarrowQuartersCount &&
fLeapMonthPatternsCount == other.fLeapMonthPatternsCount &&
fShortYearNamesCount == other.fShortYearNamesCount &&
fShortZodiacNamesCount == other.fShortZodiacNamesCount &&
@ -599,8 +605,10 @@ DateFormatSymbols::operator==(const DateFormatSymbols& other) const
fTimeSeparator == other.fTimeSeparator &&
arrayCompare(fQuarters, other.fQuarters, fQuartersCount) &&
arrayCompare(fShortQuarters, other.fShortQuarters, fShortQuartersCount) &&
arrayCompare(fNarrowQuarters, other.fNarrowQuarters, fNarrowQuartersCount) &&
arrayCompare(fStandaloneQuarters, other.fStandaloneQuarters, fStandaloneQuartersCount) &&
arrayCompare(fStandaloneShortQuarters, other.fStandaloneShortQuarters, fStandaloneShortQuartersCount) &&
arrayCompare(fStandaloneNarrowQuarters, other.fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount) &&
arrayCompare(fLeapMonthPatterns, other.fLeapMonthPatterns, fLeapMonthPatternsCount) &&
arrayCompare(fShortYearNames, other.fShortYearNames, fShortYearNamesCount) &&
arrayCompare(fShortZodiacNames, other.fShortZodiacNames, fShortZodiacNamesCount) &&
@ -809,8 +817,8 @@ DateFormatSymbols::getQuarters(int32_t &count, DtContextType context, DtWidthTyp
returnValue = fShortQuarters;
break;
case NARROW :
count = 0;
returnValue = NULL;
count = fNarrowQuartersCount;
returnValue = fNarrowQuarters;
break;
case DT_WIDTH_COUNT :
break;
@ -828,8 +836,8 @@ DateFormatSymbols::getQuarters(int32_t &count, DtContextType context, DtWidthTyp
returnValue = fStandaloneShortQuarters;
break;
case NARROW :
count = 0;
returnValue = NULL;
count = fStandaloneNarrowQuartersCount;
returnValue = fStandaloneNarrowQuarters;
break;
case DT_WIDTH_COUNT :
break;
@ -1178,13 +1186,11 @@ DateFormatSymbols::setQuarters(const UnicodeString* quartersArray, int32_t count
fShortQuartersCount = count;
break;
case NARROW :
/*
if (fNarrowQuarters)
delete[] fNarrowQuarters;
fNarrowQuarters = newUnicodeStringArray(count);
uprv_arrayCopy( quartersArray,fNarrowQuarters,count);
fNarrowQuartersCount = count;
*/
break;
default :
break;
@ -1207,13 +1213,11 @@ DateFormatSymbols::setQuarters(const UnicodeString* quartersArray, int32_t count
fStandaloneShortQuartersCount = count;
break;
case NARROW :
/*
if (fStandaloneNarrowQuarters)
delete[] fStandaloneNarrowQuarters;
fStandaloneNarrowQuarters = newUnicodeStringArray(count);
uprv_arrayCopy( quartersArray,fStandaloneNarrowQuarters,count);
fStandaloneNarrowQuartersCount = count;
*/
break;
default :
break;
@ -2067,10 +2071,14 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
fQuartersCount = 0;
fShortQuarters = NULL;
fShortQuartersCount = 0;
fNarrowQuarters = NULL;
fNarrowQuartersCount = 0;
fStandaloneQuarters = NULL;
fStandaloneQuartersCount = 0;
fStandaloneShortQuarters = NULL;
fStandaloneShortQuartersCount = 0;
fStandaloneNarrowQuarters = NULL;
fStandaloneNarrowQuartersCount = 0;
fLeapMonthPatterns = NULL;
fLeapMonthPatternsCount = 0;
fShortYearNames = NULL;
@ -2374,6 +2382,16 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
assignArray(fStandaloneShortQuarters, fStandaloneShortQuartersCount, fShortQuarters, fShortQuartersCount);
}
// unlike the fields above, narrow format quarters fall back on narrow standalone quarters
initField(&fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount, calendarSink,
buildResourcePath(path, gQuartersTag, gNamesStandaloneTag, gNamesNarrowTag, status), status);
initField(&fNarrowQuarters, fNarrowQuartersCount, calendarSink,
buildResourcePath(path, gQuartersTag, gNamesFormatTag, gNamesNarrowTag, status), status);
if(status == U_MISSING_RESOURCE_ERROR) {
status = U_ZERO_ERROR;
assignArray(fNarrowQuarters, fNarrowQuartersCount, fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount);
}
// ICU 3.8 or later version no longer uses localized date-time pattern characters by default (ticket#5597)
/*
// fastCopyFrom()/setTo() - see assignArray comments
@ -2482,8 +2500,10 @@ DateFormatSymbols::initializeData(const Locale& locale, const char *type, UError
initField(&fNarrowAmPms, fNarrowAmPmsCount, (const UChar *)gLastResortAmPmMarkers, kAmPmNum, kAmPmLen, status);
initField(&fQuarters, fQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
initField(&fShortQuarters, fShortQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
initField(&fNarrowQuarters, fNarrowQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
initField(&fStandaloneQuarters, fStandaloneQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
initField(&fStandaloneShortQuarters, fStandaloneShortQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
initField(&fStandaloneNarrowQuarters, fStandaloneNarrowQuartersCount, (const UChar *)gLastResortQuarters, kQuarterNum, kQuarterLen, status);
fLocalPatternChars.setTo(TRUE, gPatternChars, PATTERN_CHARS_LEN);
}
}

View file

@ -1882,7 +1882,10 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
break;
case UDAT_QUARTER_FIELD:
if (count >= 4)
if (count >= 5)
_appendSymbol(appendTo, value/3, fSymbols->fNarrowQuarters,
fSymbols->fNarrowQuartersCount);
else if (count == 4)
_appendSymbol(appendTo, value/3, fSymbols->fQuarters,
fSymbols->fQuartersCount);
else if (count == 3)
@ -1893,7 +1896,10 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
break;
case UDAT_STANDALONE_QUARTER_FIELD:
if (count >= 4)
if (count >= 5)
_appendSymbol(appendTo, value/3, fSymbols->fStandaloneNarrowQuarters,
fSymbols->fStandaloneNarrowQuartersCount);
else if (count == 4)
_appendSymbol(appendTo, value/3, fSymbols->fStandaloneQuarters,
fSymbols->fStandaloneQuartersCount);
else if (count == 3)
@ -3471,7 +3477,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
return pos.getIndex();
} else {
// count >= 3 // i.e., QQQ or QQQQ
// Want to be able to parse both short and long forms.
// Want to be able to parse short, long, and narrow forms.
// Try count == 4 first:
int32_t newStart = 0;
@ -3485,6 +3491,11 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
fSymbols->fShortQuarters, fSymbols->fShortQuartersCount, cal)) > 0)
return newStart;
}
if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) {
if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
fSymbols->fNarrowQuarters, fSymbols->fNarrowQuartersCount, cal)) > 0)
return newStart;
}
if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))
return newStart;
// else we allowing parsing as number, below
@ -3517,6 +3528,11 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
fSymbols->fStandaloneShortQuarters, fSymbols->fStandaloneShortQuartersCount, cal)) > 0)
return newStart;
}
if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) {
if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
fSymbols->fStandaloneNarrowQuarters, fSymbols->fStandaloneNarrowQuartersCount, cal)) > 0)
return newStart;
}
if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))
return newStart;
// else we allowing parsing as number, below

View file

@ -704,6 +704,10 @@ udat_getSymbols(const UDateFormat *fmt,
res = syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
break;
case UDAT_NARROW_QUARTERS:
res = syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
break;
case UDAT_STANDALONE_QUARTERS:
res = syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
break;
@ -712,6 +716,10 @@ udat_getSymbols(const UDateFormat *fmt,
res = syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
break;
case UDAT_STANDALONE_NARROW_QUARTERS:
res = syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
break;
case UDAT_CYCLIC_YEARS_WIDE:
res = syms->getYearNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
break;
@ -842,6 +850,10 @@ udat_countSymbols( const UDateFormat *fmt,
syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED);
break;
case UDAT_NARROW_QUARTERS:
syms->getQuarters(count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
break;
case UDAT_STANDALONE_QUARTERS:
syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
break;
@ -850,6 +862,10 @@ udat_countSymbols( const UDateFormat *fmt,
syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED);
break;
case UDAT_STANDALONE_NARROW_QUARTERS:
syms->getQuarters(count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
break;
case UDAT_CYCLIC_YEARS_WIDE:
syms->getYearNames(count, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE);
break;
@ -1048,6 +1064,13 @@ public:
setSymbol(syms->fShortQuarters, syms->fShortQuartersCount, index, value, valueLength, errorCode);
}
static void
setNarrowQuarter(DateFormatSymbols *syms, int32_t index,
const UChar *value, int32_t valueLength, UErrorCode &errorCode)
{
setSymbol(syms->fNarrowQuarters, syms->fNarrowQuartersCount, index, value, valueLength, errorCode);
}
static void
setStandaloneQuarter(DateFormatSymbols *syms, int32_t index,
const UChar *value, int32_t valueLength, UErrorCode &errorCode)
@ -1062,6 +1085,13 @@ public:
setSymbol(syms->fStandaloneShortQuarters, syms->fStandaloneShortQuartersCount, index, value, valueLength, errorCode);
}
static void
setStandaloneNarrowQuarter(DateFormatSymbols *syms, int32_t index,
const UChar *value, int32_t valueLength, UErrorCode &errorCode)
{
setSymbol(syms->fStandaloneNarrowQuarters, syms->fStandaloneNarrowQuartersCount, index, value, valueLength, errorCode);
}
static void
setShortYearNames(DateFormatSymbols *syms, int32_t index,
const UChar *value, int32_t valueLength, UErrorCode &errorCode)
@ -1179,6 +1209,10 @@ udat_setSymbols( UDateFormat *format,
DateFormatSymbolsSingleSetter::setShortQuarter(syms, index, value, valueLength, *status);
break;
case UDAT_NARROW_QUARTERS:
DateFormatSymbolsSingleSetter::setNarrowQuarter(syms, index, value, valueLength, *status);
break;
case UDAT_STANDALONE_QUARTERS:
DateFormatSymbolsSingleSetter::setStandaloneQuarter(syms, index, value, valueLength, *status);
break;
@ -1187,6 +1221,10 @@ udat_setSymbols( UDateFormat *format,
DateFormatSymbolsSingleSetter::setStandaloneShortQuarter(syms, index, value, valueLength, *status);
break;
case UDAT_STANDALONE_NARROW_QUARTERS:
DateFormatSymbolsSingleSetter::setStandaloneNarrowQuarter(syms, index, value, valueLength, *status);
break;
case UDAT_CYCLIC_YEARS_ABBREVIATED:
DateFormatSymbolsSingleSetter::setShortYearNames(syms, index, value, valueLength, *status);
break;

View file

@ -388,8 +388,7 @@ public:
* Gets quarter strings by width and context. For example: "1st Quarter", "2nd Quarter", etc.
* @param count Filled in with length of the array.
* @param context The formatting context, either FORMAT or STANDALONE
* @param width The width of returned strings, either WIDE or ABBREVIATED. There
* are no NARROW quarters.
* @param width The width of returned strings, either WIDE, ABBREVIATED, or NARROW.
* @return the quarter strings. (DateFormatSymbols retains ownership.)
* @stable ICU 3.6
*/
@ -401,8 +400,7 @@ public:
* @param quarters The new quarter strings. (not adopted; caller retains ownership)
* @param count Filled in with length of the array.
* @param context The formatting context, either FORMAT or STANDALONE
* @param width The width of returned strings, either WIDE or ABBREVIATED. There
* are no NARROW quarters.
* @param width The width of returned strings, either WIDE, ABBREVIATED, or NARROW.
* @stable ICU 3.6
*/
void setQuarters(const UnicodeString* quarters, int32_t count, DtContextType context, DtWidthType width);
@ -775,6 +773,13 @@ private:
UnicodeString *fShortQuarters;
int32_t fShortQuartersCount;
/**
* Narrow quarters. For example: "1", "2", etc.
* (In many, but not all, locales, this is the same as "Q", but there are locales for which this isn't true.)
*/
UnicodeString *fNarrowQuarters;
int32_t fNarrowQuartersCount;
/**
* Standalone quarter strings. For example: "1st quarter", "2nd quarter", etc.
*/
@ -787,6 +792,13 @@ private:
UnicodeString *fStandaloneShortQuarters;
int32_t fStandaloneShortQuartersCount;
/**
* Standalone narrow quarter strings. For example: "1", "2", etc.
* (In many, but not all, locales, this is the same as "q", but there are locales for which this isn't true.)
*/
UnicodeString *fStandaloneNarrowQuarters;
int32_t fStandaloneNarrowQuartersCount;
/**
* All leap month patterns, for example "{0}bis".
*/

View file

@ -1530,7 +1530,21 @@ typedef enum UDateFormatSymbolType {
* udat_setSymbols not supported for UDAT_ZODIAC_NAMES_NARROW)
* @stable ICU 54
*/
UDAT_ZODIAC_NAMES_NARROW
UDAT_ZODIAC_NAMES_NARROW,
#ifndef U_HIDE_DRAFT_API
/**
* The narrow quarter names, for example 1
* @draft ICU 70
*/
UDAT_NARROW_QUARTERS,
/**
* The narrow standalone quarter names, for example 1
* @draft ICU 70
*/
UDAT_STANDALONE_NARROW_QUARTERS
#endif // U_HIDE_DRAFT_API
} UDateFormatSymbolType;
struct UDateFormatSymbols;

View file

@ -44,6 +44,7 @@ static void TestParseErrorReturnValue(void);
static void TestFormatForFields(void);
static void TestForceGannenNumbering(void);
static void TestMapDateToCalFields(void);
static void TestNarrowQuarters(void);
void addDateForTest(TestNode** root);
@ -65,6 +66,7 @@ void addDateForTest(TestNode** root)
TESTCASE(TestFormatForFields);
TESTCASE(TestForceGannenNumbering);
TESTCASE(TestMapDateToCalFields);
TESTCASE(TestNarrowQuarters);
}
/* Testing the DateFormat API */
static void TestDateFormat()
@ -579,7 +581,7 @@ static void TestRelativeDateFormat()
/*Testing udat_getSymbols() and udat_setSymbols() and udat_countSymbols()*/
static void TestSymbols()
{
UDateFormat *def, *fr, *zhChiCal;
UDateFormat *def, *fr, *zhChiCal, *esMX;
UErrorCode status = U_ZERO_ERROR;
UChar *value=NULL;
UChar *result = NULL;
@ -618,7 +620,15 @@ static void TestSymbols()
myErrorName(status) );
return;
}
/*creating a dateformat with es_MX locale */
log_verbose("\ncreating a date format with es_MX locale\n");
esMX = udat_open(UDAT_SHORT, UDAT_NONE, "es_MX", NULL, 0, NULL, 0, &status);
if(U_FAILURE(status))
{
log_data_err("error in creating the dateformat using no date, short time, locale es_MX -> %s (Are you missing data?)\n",
myErrorName(status) );
return;
}
/*Testing countSymbols, getSymbols and setSymbols*/
log_verbose("\nTesting countSymbols\n");
@ -683,6 +693,8 @@ static void TestSymbols()
VerifygetSymbols(def, UDAT_QUARTERS, 3, "4th quarter");
VerifygetSymbols(fr, UDAT_SHORT_QUARTERS, 1, "T2");
VerifygetSymbols(def, UDAT_SHORT_QUARTERS, 2, "Q3");
VerifygetSymbols(esMX, UDAT_STANDALONE_NARROW_QUARTERS, 1, "2T");
VerifygetSymbols(def, UDAT_NARROW_QUARTERS, 2, "3");
VerifygetSymbols(zhChiCal, UDAT_CYCLIC_YEARS_ABBREVIATED, 0, "\\u7532\\u5B50");
VerifygetSymbols(zhChiCal, UDAT_CYCLIC_YEARS_NARROW, 59, "\\u7678\\u4EA5");
VerifygetSymbols(zhChiCal, UDAT_ZODIAC_NAMES_ABBREVIATED, 0, "\\u9F20");
@ -803,8 +815,10 @@ free(pattern);
VerifysetSymbols(fr, UDAT_STANDALONE_NARROW_MONTHS, 2, "M");
VerifysetSymbols(fr, UDAT_QUARTERS, 0, "1. Quart");
VerifysetSymbols(fr, UDAT_SHORT_QUARTERS, 1, "QQ2");
VerifysetSymbols(fr, UDAT_NARROW_QUARTERS, 1, "!2");
VerifysetSymbols(fr, UDAT_STANDALONE_QUARTERS, 2, "3rd Quar.");
VerifysetSymbols(fr, UDAT_STANDALONE_SHORT_QUARTERS, 3, "4QQ");
VerifysetSymbols(fr, UDAT_STANDALONE_NARROW_QUARTERS, 3, "!4");
VerifysetSymbols(zhChiCal, UDAT_CYCLIC_YEARS_ABBREVIATED, 1, "yi-chou");
VerifysetSymbols(zhChiCal, UDAT_ZODIAC_NAMES_ABBREVIATED, 1, "Ox");
@ -827,6 +841,7 @@ free(pattern);
udat_close(fr);
udat_close(def);
udat_close(zhChiCal);
udat_close(esMX);
if(result != NULL) {
free(result);
result = NULL;
@ -1943,4 +1958,63 @@ static void TestMapDateToCalFields(void){
}
}
static void TestNarrowQuarters(void) {
// Test for rdar://79238094
const UChar* testCases[] = {
u"en_US", u"QQQQ y", u"1st quarter 1970",
u"en_US", u"QQQ y", u"Q1 1970",
u"en_US", u"QQQQQ y", u"1 1970",
u"es_MX", u"QQQQ y", u"1.er trimestre 1970",
u"es_MX", u"QQQ y", u"T1 1970",
u"es_MX", u"QQQQQ y", u"1 1970",
u"en_US", u"qqqq", u"1st quarter",
u"en_US", u"qqq", u"Q1",
u"en_US", u"qqqqq", u"1",
u"es_MX", u"qqqq", u"1.er trimestre",
u"es_MX", u"qqq", u"T1",
u"es_MX", u"qqqqq", u"1T",
};
UErrorCode err = U_ZERO_ERROR;
UChar result[100];
UDate parsedDate = 0;
UDate expectedFormatParsedDate = 0;
UDate expectedStandaloneParsedDate = 0;
for (int32_t i = 0; i < UPRV_LENGTHOF(testCases); i += 3) {
const UChar* localeID = testCases[i];
const UChar* pattern = testCases[i + 1];
const UChar* expectedResult = testCases[i + 2];
err = U_ZERO_ERROR;
UDateFormat* df = udat_open(UDAT_PATTERN, UDAT_PATTERN, austrdup(localeID), u"UTC", 0, pattern, -1, &err);
udat_format(df, 0, result, 100, NULL, &err);
if (assertSuccess("Formatting date failed", &err)) {
assertUEquals("Wrong formatting result", expectedResult, result);
}
bool patternIsStandaloneQuarter = u_strchr(pattern, u'q') != NULL;
parsedDate = udat_parse(df, expectedResult, -1, NULL, &err);
if (!patternIsStandaloneQuarter && expectedFormatParsedDate == 0) {
expectedFormatParsedDate = parsedDate;
} else if (patternIsStandaloneQuarter && expectedStandaloneParsedDate == 0) {
expectedStandaloneParsedDate = parsedDate;
}
if (assertSuccess("Parsing date failed", &err)) {
if (patternIsStandaloneQuarter) {
assertIntEquals("Wrong parsing result", expectedStandaloneParsedDate, parsedDate);
} else {
assertIntEquals("Wrong parsing result", expectedFormatParsedDate, parsedDate);
}
}
udat_close(df);
}
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -1892,21 +1892,34 @@ void DateFormatTest::TestQuarters()
const char *EN_DATA[] = {
"yyyy MM dd",
"Q", "fp", "1970 01 01", "1", "1970 01 01",
"QQ", "fp", "1970 04 01", "02", "1970 04 01",
"QQQ", "fp", "1970 07 01", "Q3", "1970 07 01",
"QQQQ", "fp", "1970 10 01", "4th quarter", "1970 10 01",
"Q", "fp", "1970 01 01", "1", "1970 01 01",
"QQ", "fp", "1970 04 01", "02", "1970 04 01",
"QQQ", "fp", "1970 07 01", "Q3", "1970 07 01",
"QQQQ", "fp", "1970 10 01", "4th quarter", "1970 10 01",
"QQQQQ", "fp", "1970 10 01", "4", "1970 10 01",
"q", "fp", "1970 01 01", "1", "1970 01 01",
"qq", "fp", "1970 04 01", "02", "1970 04 01",
"qqq", "fp", "1970 07 01", "Q3", "1970 07 01",
"qqqq", "fp", "1970 10 01", "4th quarter", "1970 10 01",
"q", "fp", "1970 01 01", "1", "1970 01 01",
"qq", "fp", "1970 04 01", "02", "1970 04 01",
"qqq", "fp", "1970 07 01", "Q3", "1970 07 01",
"qqqq", "fp", "1970 10 01", "4th quarter", "1970 10 01",
"qqqqq", "fp", "1970 10 01", "4", "1970 10 01",
"Qyy", "fp", "2015 04 01", "215", "2015 04 01",
"QQyy", "fp", "2015 07 01", "0315", "2015 07 01",
"Qyy", "fp", "2015 04 01", "215", "2015 04 01",
"QQyy", "fp", "2015 07 01", "0315", "2015 07 01",
};
const char *ES_MX_DATA[] = {
"yyyy MM dd",
"QQQQ y", "fp", "1970 01 01", "1.er trimestre 1970", "1970 01 01",
"QQQ y", "fp", "1970 01 01", "T1 1970", "1970 01 01",
"QQQQQ y", "fp", "1970 01 01", "1 1970", "1970 01 01",
"qqqq", "fp", "1970 01 01", "1.er trimestre", "1970 01 01",
"qqq", "fp", "1970 01 01", "T1", "1970 01 01",
"qqqqq", "fp", "1970 01 01", "1T", "1970 01 01",
};
expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
expect(ES_MX_DATA, UPRV_LENGTHOF(ES_MX_DATA), Locale("es", "MX", ""));
}
/**

View file

@ -348,6 +348,13 @@ void IntlTestDateFormatSymbols::TestSymbols(/* char *par */)
errln("ERROR: setQuarters(FORMAT, ABBREVIATED) failed");
}
const UnicodeString *narrowQuarters = en.getQuarters(count,DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
fr2.setQuarters(narrowQuarters, count, DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW);
if( *en.getQuarters(count,DateFormatSymbols::FORMAT, DateFormatSymbols::NARROW) !=
*fr2.getQuarters(count,DateFormatSymbols::FORMAT ,DateFormatSymbols::NARROW )) {
errln("ERROR: setQuarters(FORMAT, NARROW) failed");
}
const UnicodeString *standaloneWideQuarters = en.getQuarters(count,DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
fr.setQuarters(standaloneWideQuarters, count, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE);
if( *en.getQuarters(count,DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE) !=
@ -362,6 +369,13 @@ void IntlTestDateFormatSymbols::TestSymbols(/* char *par */)
errln("ERROR: setQuarters(STANDALONE, ABBREVIATED) failed");
}
const UnicodeString *standaloneNarrowQuarters = en.getQuarters(count,DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
fr2.setQuarters(standaloneNarrowQuarters, count, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW);
if( *en.getQuarters(count,DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW) !=
*fr2.getQuarters(count,DateFormatSymbols::STANDALONE ,DateFormatSymbols::NARROW )) {
errln("ERROR: setQuarters(STANDALONE, NARROW) failed");
}
const UnicodeString *ampms = en.getAmPmStrings(count);
fr.setAmPmStrings(ampms, count);
if( *en.getAmPmStrings(count) != *fr.getAmPmStrings(count)) {

View file

@ -515,6 +515,13 @@ public class DateFormatSymbols implements Serializable, Cloneable {
*/
String shortQuarters[] = null;
/**
* Narrow quarter names. For example: "1", "2", "3", "4". An array
* of 4 strings indexed by the month divided by 3.
* @serial
*/
String narrowQuarters[] = null;
/**
* Full quarter names. For example: "1st Quarter", "2nd Quarter", "3rd Quarter",
* "4th Quarter". An array of 4 strings, indexed by the month divided by 3.
@ -529,6 +536,13 @@ public class DateFormatSymbols implements Serializable, Cloneable {
*/
String standaloneShortQuarters[] = null;
/**
* Standalone narrow quarter names. For example: "1", "2", "3", "4". An array
* of 4 strings indexed by the month divided by 3.
* @serial
*/
String standaloneNarrowQuarters[] = null;
/**
* Standalone full quarter names. For example: "1st Quarter", "2nd Quarter", "3rd Quarter",
* "4th Quarter". An array of 4 strings, indexed by the month divided by 3.
@ -1042,7 +1056,7 @@ public class DateFormatSymbols implements Serializable, Cloneable {
* {@icu} Returns quarter strings. For example: "1st Quarter", "2nd Quarter", etc.
* @param context The quarter context, FORMAT or STANDALONE.
* @param width The width or the returned quarter string,
* either WIDE or ABBREVIATED. There are no NARROW quarters.
* WIDE, NARROW, or ABBREVIATED.
* @return the quarter strings.
* @stable ICU 3.6
*/
@ -1059,7 +1073,7 @@ public class DateFormatSymbols implements Serializable, Cloneable {
returnValue = shortQuarters;
break;
case NARROW :
returnValue = null;
returnValue = narrowQuarters;
break;
}
break;
@ -1074,7 +1088,7 @@ public class DateFormatSymbols implements Serializable, Cloneable {
returnValue = standaloneShortQuarters;
break;
case NARROW:
returnValue = null;
returnValue = standaloneNarrowQuarters;
break;
}
break;
@ -1090,7 +1104,7 @@ public class DateFormatSymbols implements Serializable, Cloneable {
* @param newQuarters the new quarter strings.
* @param context The formatting context, FORMAT or STANDALONE.
* @param width The width of the quarter string,
* either WIDE or ABBREVIATED. There are no NARROW quarters.
* WIDE, NARROW, or ABBREVIATED.
* @stable ICU 3.8
*/
public void setQuarters(String[] newQuarters, int context, int width) {
@ -1104,7 +1118,7 @@ public class DateFormatSymbols implements Serializable, Cloneable {
shortQuarters = duplicate(newQuarters);
break;
case NARROW :
//narrowQuarters = duplicate(newQuarters);
narrowQuarters = duplicate(newQuarters);
break;
default : // HANDLE SHORT, etc.
break;
@ -1119,7 +1133,7 @@ public class DateFormatSymbols implements Serializable, Cloneable {
standaloneShortQuarters = duplicate(newQuarters);
break;
case NARROW :
//standaloneNarrowQuarters = duplicate(newQuarters);
standaloneNarrowQuarters = duplicate(newQuarters);
break;
default : // HANDLE SHORT, etc.
break;
@ -1580,8 +1594,10 @@ public class DateFormatSymbols implements Serializable, Cloneable {
this.ampmsNarrow = dfs.ampmsNarrow;
this.timeSeparator = dfs.timeSeparator;
this.shortQuarters = dfs.shortQuarters;
this.narrowQuarters = dfs.narrowQuarters;
this.quarters = dfs.quarters;
this.standaloneShortQuarters = dfs.standaloneShortQuarters;
this.standaloneNarrowQuarters = dfs.standaloneNarrowQuarters;
this.standaloneQuarters = dfs.standaloneQuarters;
this.leapMonthPatterns = dfs.leapMonthPatterns;
this.shortYearNames = dfs.shortYearNames;
@ -1982,9 +1998,11 @@ public class DateFormatSymbols implements Serializable, Cloneable {
quarters = arrays.get("quarters/format/wide");
shortQuarters = arrays.get("quarters/format/abbreviated");
narrowQuarters = arrays.get("quarters/format/narrow");
standaloneQuarters = arrays.get("quarters/stand-alone/wide");
standaloneShortQuarters = arrays.get("quarters/stand-alone/abbreviated");
standaloneNarrowQuarters = arrays.get("quarters/stand-alone/narrow");
abbreviatedDayPeriods = loadDayPeriodStrings(maps.get("dayPeriod/format/abbreviated"));
wideDayPeriods = loadDayPeriodStrings(maps.get("dayPeriod/format/wide"));

View file

@ -1899,7 +1899,9 @@ public class SimpleDateFormat extends DateFormat {
}
break;
case 27: // 'Q' - QUARTER
if (count >= 4) {
if (count >= 5) {
safeAppend(formatData.narrowQuarters, value/3, buf);
} else if (count == 4) {
safeAppend(formatData.quarters, value/3, buf);
} else if (count == 3) {
safeAppend(formatData.shortQuarters, value/3, buf);
@ -1908,7 +1910,9 @@ public class SimpleDateFormat extends DateFormat {
}
break;
case 28: // 'q' - STANDALONE QUARTER
if (count >= 4) {
if (count >= 5) {
safeAppend(formatData.standaloneNarrowQuarters, value/3, buf);
} else if (count == 4) {
safeAppend(formatData.standaloneQuarters, value/3, buf);
} else if (count == 3) {
safeAppend(formatData.standaloneShortQuarters, value/3, buf);
@ -3614,7 +3618,7 @@ public class SimpleDateFormat extends DateFormat {
return pos.getIndex();
} else {
// count >= 3 // i.e., QQQ or QQQQ
// Want to be able to parse both short and long forms.
// Want to be able to parse short, long, and narrow forms.
// Try count == 4 first:
int newStart = 0;
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
@ -3624,8 +3628,14 @@ public class SimpleDateFormat extends DateFormat {
}
// count == 4 failed, now try count == 3
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
if((newStart = matchQuarterString(text, start, Calendar.MONTH, formatData.shortQuarters, cal)) > 0) {
return newStart;
}
}
// count == 3 failed, now try count == 5
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 5) {
return matchQuarterString(text, start, Calendar.MONTH,
formatData.shortQuarters, cal);
formatData.narrowQuarters, cal);
}
return newStart;
}
@ -3640,7 +3650,7 @@ public class SimpleDateFormat extends DateFormat {
return pos.getIndex();
} else {
// count >= 3 // i.e., qqq or qqqq
// Want to be able to parse both short and long forms.
// Want to be able to parse short, long, and narrow forms.
// Try count == 4 first:
int newStart = 0;
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
@ -3650,8 +3660,14 @@ public class SimpleDateFormat extends DateFormat {
}
// count == 4 failed, now try count == 3
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
if((newStart = matchQuarterString(text, start, Calendar.MONTH, formatData.standaloneShortQuarters, cal)) > 0) {
return newStart;
}
}
// count == 3 failed, now try count == 5
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 5) {
return matchQuarterString(text, start, Calendar.MONTH,
formatData.standaloneShortQuarters, cal);
formatData.standaloneNarrowQuarters, cal);
}
return newStart;
}

View file

@ -3154,21 +3154,35 @@ public class DateFormatTest extends TestFmwk {
String EN_DATA[] = {
"yyyy MM dd",
"Q", "fp", "1970 01 01", "1", "1970 01 01",
"QQ", "fp", "1970 04 01", "02", "1970 04 01",
"QQQ", "fp", "1970 07 01", "Q3", "1970 07 01",
"QQQQ", "fp", "1970 10 01", "4th quarter", "1970 10 01",
"Q", "fp", "1970 01 01", "1", "1970 01 01",
"QQ", "fp", "1970 04 01", "02", "1970 04 01",
"QQQ", "fp", "1970 07 01", "Q3", "1970 07 01",
"QQQQ", "fp", "1970 10 01", "4th quarter", "1970 10 01",
"QQQQQ", "fp", "1970 10 01", "4", "1970 10 01",
"q", "fp", "1970 01 01", "1", "1970 01 01",
"qq", "fp", "1970 04 01", "02", "1970 04 01",
"qqq", "fp", "1970 07 01", "Q3", "1970 07 01",
"qqqq", "fp", "1970 10 01", "4th quarter", "1970 10 01",
"q", "fp", "1970 01 01", "1", "1970 01 01",
"qq", "fp", "1970 04 01", "02", "1970 04 01",
"qqq", "fp", "1970 07 01", "Q3", "1970 07 01",
"qqqq", "fp", "1970 10 01", "4th quarter", "1970 10 01",
"qqqqq", "fp", "1970 10 01", "4", "1970 10 01",
"Qyy", "fp", "2015 04 01", "215", "2015 04 01",
"QQyy", "fp", "2015 07 01", "0315", "2015 07 01",
};
String ES_MX_DATA[] = {
"yyyy MM dd",
// Test commented out because of ICU-21671
// "QQQQ y", "fp", "1970 01 01", "1.er trimestre 1970", "1970 01 01",
"QQQ y", "fp", "1970 01 01", "T1 1970", "1970 01 01",
"QQQQQ y", "fp", "1970 01 01", "1 1970", "1970 01 01",
"qqqq", "fp", "1970 01 01", "1.er trimestre", "1970 01 01",
"qqq", "fp", "1970 01 01", "T1", "1970 01 01",
"qqqqq", "fp", "1970 01 01", "1T", "1970 01 01",
};
expect(EN_DATA, new Locale("en", "", ""));
expect(ES_MX_DATA, new Locale("es", "MX", ""));
}
/**

View file

@ -451,6 +451,21 @@ public class IntlTestDateFormatSymbols extends TestFmwk
}
}
final String[] narrowQuarters = en.getQuarters(DateFormatSymbols.FORMAT,DateFormatSymbols.NARROW);
fr2.setQuarters(narrowQuarters,DateFormatSymbols.FORMAT,DateFormatSymbols.NARROW);
final String[] narrowQuarters1 = fr2.getQuarters(DateFormatSymbols.FORMAT,DateFormatSymbols.NARROW);
count = narrowQuarters.length;
if( count != narrowQuarters1.length) {
errln("ERROR: setQuarters(FORMAT, NARROW) failed (different size array)");
}
else {
for(int i = 0; i < count; i++) {
if(! narrowQuarters[i].equals(narrowQuarters1[i])) {
errln("ERROR: setQuarters(FORMAT, NARROW) failed (different string values)");
}
}
}
final String[] standaloneQuarters = en.getQuarters(DateFormatSymbols.STANDALONE,DateFormatSymbols.WIDE);
fr.setQuarters(standaloneQuarters,DateFormatSymbols.STANDALONE,DateFormatSymbols.WIDE);
final String[] standaloneQuarters1 = fr.getQuarters(DateFormatSymbols.STANDALONE,DateFormatSymbols.WIDE);
@ -481,6 +496,21 @@ public class IntlTestDateFormatSymbols extends TestFmwk
}
}
final String[] standaloneNarrowQuarters = en.getQuarters(DateFormatSymbols.STANDALONE,DateFormatSymbols.NARROW);
fr2.setQuarters(standaloneNarrowQuarters,DateFormatSymbols.STANDALONE,DateFormatSymbols.NARROW);
final String[] standaloneNarrowQuarters1 = fr2.getQuarters(DateFormatSymbols.STANDALONE,DateFormatSymbols.NARROW);
count = standaloneNarrowQuarters.length;
if( count != standaloneNarrowQuarters1.length) {
errln("ERROR: setQuarters(STANDALONE, NARROW) failed (different size array)");
}
else {
for(int i = 0; i < count; i++) {
if(! standaloneNarrowQuarters[i].equals(standaloneNarrowQuarters1[i])) {
errln("ERROR: setQuarters(STANDALONE, NARROW) failed (different string values)");
}
}
}
final String[] ampms = en.getAmPmStrings();
fr.setAmPmStrings(ampms);
final String[] ampms1 = fr.getAmPmStrings();