ICU-21099 udat_toCalendarDateField should handle all UDateFormatFields and out of range

This commit is contained in:
Peter Edberg 2020-04-26 18:24:14 -07:00 committed by pedberg-icu
parent a951ab59c7
commit d39899350d
3 changed files with 57 additions and 5 deletions

View File

@ -82,13 +82,18 @@ static UCalendarDateFields gDateFieldMapping[] = {
UCAL_ZONE_OFFSET, // UDAT_TIMEZONE_ISO_FIELD = 32 (also UCAL_DST_OFFSET)
UCAL_ZONE_OFFSET, // UDAT_TIMEZONE_ISO_LOCAL_FIELD = 33 (also UCAL_DST_OFFSET)
UCAL_EXTENDED_YEAR, // UDAT_RELATED_YEAR_FIELD = 34 (not an exact match)
UCAL_FIELD_COUNT, // UDAT_FIELD_COUNT = 35
UCAL_FIELD_COUNT, // UDAT_AM_PM_MIDNIGHT_NOON_FIELD=35 (no match)
UCAL_FIELD_COUNT, // UDAT_FLEXIBLE_DAY_PERIOD_FIELD=36 (no match)
UCAL_FIELD_COUNT, // UDAT_TIME_SEPARATOR_FIELD = 37 (no match)
// UDAT_FIELD_COUNT = 38 as of ICU 67
// UCAL_IS_LEAP_MONTH is not the target of a mapping
};
U_CAPI UCalendarDateFields U_EXPORT2
udat_toCalendarDateField(UDateFormatField field) {
return gDateFieldMapping[field];
static_assert(UDAT_FIELD_COUNT == UPRV_LENGTHOF(gDateFieldMapping),
"UDateFormatField and gDateFieldMapping should have the same number of entries and be kept in sync.");
return (field >= UDAT_ERA_FIELD && field < UPRV_LENGTHOF(gDateFieldMapping))? gDateFieldMapping[field]: UCAL_FIELD_COUNT;
}
/* For now- one opener. */

View File

@ -832,10 +832,24 @@ typedef enum UDateFormatField {
/**
* Maps from a UDateFormatField to the corresponding UCalendarDateFields.
* Note: since the mapping is many-to-one, there is no inverse mapping.
*
* Note 1: Since the mapping is many-to-one, there is no inverse mapping.
*
* Note 2: There is no UErrorCode parameter, so in case of error (UDateFormatField is
* unknown or has no corresponding UCalendarDateFields value), the function returns the
* current value of UCAL_FIELD_COUNT. However, that value may change from release to
* release and is consequently deprecated. For a future-proof runtime way of checking
* for errors:
* a) First save the value returned by the function when it is passed an invalid value
* such as "(UDateFormatField)-1".
* b) Then, to test for errors when passing some other UDateFormatField value, check
* whether the function returns that saved value.
*
* @param field the UDateFormatField.
* @return the UCalendarDateField. This will be UCAL_FIELD_COUNT in case
* of error (e.g., the input field is UDAT_FIELD_COUNT).
* @return the UCalendarDateField. In case of error (UDateFormatField is unknown or has
* no corresponding UCalendarDateFields value) this will be the current value of
* UCAL_FIELD_COUNT, but that value may change from release to release.
* See Note 2 above.
* @stable ICU 4.4
*/
U_CAPI UCalendarDateFields U_EXPORT2

View File

@ -43,6 +43,7 @@ static void TestCalendarDateParse(void);
static void TestParseErrorReturnValue(void);
static void TestFormatForFields(void);
static void TestForceGannenNumbering(void);
static void TestMapDateToCalFields(void);
void addDateForTest(TestNode** root);
@ -63,6 +64,7 @@ void addDateForTest(TestNode** root)
TESTCASE(TestParseErrorReturnValue);
TESTCASE(TestFormatForFields);
TESTCASE(TestForceGannenNumbering);
TESTCASE(TestMapDateToCalFields);
}
/* Testing the DateFormat API */
static void TestDateFormat()
@ -1905,4 +1907,35 @@ static void TestForceGannenNumbering(void) {
udatpg_close(dtpgen);
}
}
typedef struct {
UChar patternChar; // for future use
UDateFormatField dateField;
UCalendarDateFields calField;
} PatternCharToFieldsItem;
static const PatternCharToFieldsItem patCharToFieldsItems[] = {
{ u'G', UDAT_ERA_FIELD, UCAL_ERA },
{ u'y', UDAT_YEAR_FIELD, UCAL_YEAR },
{ u'Y', UDAT_YEAR_WOY_FIELD, UCAL_YEAR_WOY },
{ u'Q', UDAT_QUARTER_FIELD, UCAL_MONTH },
{ u'H', UDAT_HOUR_OF_DAY0_FIELD, UCAL_HOUR_OF_DAY },
{ u'r', UDAT_RELATED_YEAR_FIELD, UCAL_EXTENDED_YEAR },
{ u'B', UDAT_FLEXIBLE_DAY_PERIOD_FIELD, UCAL_FIELD_COUNT },
{ u'$', UDAT_FIELD_COUNT, UCAL_FIELD_COUNT },
{ 0xFFFF, (UDateFormatField)-1, UCAL_FIELD_COUNT }, // patternChar ignored here
{ (UChar)0, (UDateFormatField)0, (UCalendarDateFields)0 } // terminator
};
static void TestMapDateToCalFields(void){
const PatternCharToFieldsItem* itemPtr;
for ( itemPtr=patCharToFieldsItems; itemPtr->patternChar!=(UChar)0; itemPtr++) {
UCalendarDateFields calField = udat_toCalendarDateField(itemPtr->dateField);
if (calField != itemPtr->calField) {
log_err("for pattern char 0x%04X, dateField %d, expect calField %d and got %d\n",
itemPtr->patternChar, itemPtr->dateField, itemPtr->calField, calField);
}
}
}
#endif /* #if !UCONFIG_NO_FORMATTING */