ICU-20739 Force seconds if the skeleton has fractional seconds

This commit is contained in:
Mihai Nita 2019-11-08 21:25:37 +00:00
parent cfb298f035
commit 17d23d71c0
4 changed files with 81 additions and 1 deletions
icu4c/source
i18n
test/intltest
icu4j/main
classes/core/src/com/ibm/icu/text
tests/core/src/com/ibm/icu/dev/test/format

View file

@ -2162,6 +2162,25 @@ DateTimeMatcher::set(const UnicodeString& pattern, FormatParser* fp, PtnSkeleton
}
skeletonResult.type[field] = subField;
}
// #20739, we have a skeleton with milliseconde, but no seconds
if (!skeletonResult.original.isFieldEmpty(UDATPG_FRACTIONAL_SECOND_FIELD)
&& skeletonResult.original.isFieldEmpty(UDATPG_SECOND_FIELD)) {
// Force the use of seconds
for (i = 0; dtTypes[i].patternChar != 0; i++) {
if (dtTypes[i].field == UDATPG_SECOND_FIELD) {
// first entry for UDATPG_SECOND_FIELD
skeletonResult.original.populate(UDATPG_SECOND_FIELD, dtTypes[i].patternChar, dtTypes[i].minLen);
skeletonResult.baseOriginal.populate(UDATPG_SECOND_FIELD, dtTypes[i].patternChar, dtTypes[i].minLen);
// We add value.length, same as above, when type is first initialized.
// The value we want to "fake" here is "s", and 1 means "s".length()
int16_t subField = dtTypes[i].type;
skeletonResult.type[UDATPG_SECOND_FIELD] = (subField > 0) ? subField + 1 : subField;
break;
}
}
}
// #13183, handle special behavior for day period characters (a, b, B)
if (!skeletonResult.original.isFieldEmpty(UDATPG_HOUR_FIELD)) {
if (skeletonResult.original.getFieldChar(UDATPG_HOUR_FIELD)==LOW_H || skeletonResult.original.getFieldChar(UDATPG_HOUR_FIELD)==CAP_K) {

View file

@ -4912,7 +4912,22 @@ void DateFormatTest::TestPatternFromSkeleton() {
{Locale::getEnglish(), "jjmm", "h:mm a"},
{Locale::getEnglish(), "JJmm", "hh:mm"},
{Locale::getGerman(), "jjmm", "HH:mm"},
{Locale::getGerman(), "JJmm", "HH:mm"}
{Locale::getGerman(), "JJmm", "HH:mm"},
// Ticket #20739
{Locale::getEnglish(), "SSSSm", "mm:ss.SSSS"},
{Locale::getEnglish(), "mSSSS", "mm:ss.SSSS"},
{Locale::getEnglish(), "SSSm", "mm:ss.SSS"},
{Locale::getEnglish(), "mSSS", "mm:ss.SSS"},
{Locale::getEnglish(), "SSm", "mm:ss.SS"},
{Locale::getEnglish(), "mSS", "mm:ss.SS"},
{Locale::getEnglish(), "Sm", "mm:ss.S"},
{Locale::getEnglish(), "mS", "mm:ss.S"},
{Locale::getEnglish(), "S", "S"},
{Locale::getEnglish(), "SS", "SS"},
{Locale::getEnglish(), "SSS", "SSS"},
{Locale::getEnglish(), "SSSS", "SSSS"},
{Locale::getEnglish(), "jmsSSS", "h:mm:ss.SSS a"},
{Locale::getEnglish(), "jmSSS", "h:mm:ss.SSS a"}
};
for (size_t i = 0; i < UPRV_LENGTHOF(TESTDATA); i++) {

View file

@ -2649,6 +2649,25 @@ public class DateTimePatternGenerator implements Freezable<DateTimePatternGenera
if (subField > 0) subField += value.length();
type[field] = subField;
}
// #20739, we have a skeleton with milliseconde, but no seconds
if (!original.isFieldEmpty(FRACTIONAL_SECOND) && original.isFieldEmpty(SECOND)) {
// Force the use of seconds
for (int i = 0; i < types.length; ++i) {
int[] row = types[i];
if (row[1] == SECOND) {
// first entry for SECOND
original.populate(SECOND, (char)row[0], row[3]);
baseOriginal.populate(SECOND, (char)row[0], row[3]);
// We add value.length, same as above, when type is first initialized.
// The value we want to "fake" here is "s", and 1 means "s".length()
int subField = row[2];
type[SECOND] = (subField > 0) ? subField + 1 : subField;
break;
}
}
}
// #13183, handle special behavior for day period characters (a, b, B)
if (!original.isFieldEmpty(HOUR)) {
if (original.getFieldChar(HOUR)=='h' || original.getFieldChar(HOUR)=='K') {

View file

@ -5431,4 +5431,31 @@ public class DateFormatTest extends TestFmwk {
dfmt.parse(inDate, pos);
assertEquals("Error index", inDate.length(), pos.getErrorIndex());
}
@Test
public void test20739_MillisecondsWithoutSeconds() {
String[][] cases = new String[][]{
{"SSSSm", "mm:ss.SSSS"},
{"mSSSS", "mm:ss.SSSS"},
{"SSSm", "mm:ss.SSS"},
{"mSSS", "mm:ss.SSS"},
{"SSm", "mm:ss.SS"},
{"mSS", "mm:ss.SS"},
{"Sm", "mm:ss.S"},
{"mS", "mm:ss.S"},
{"S", "S"},
{"SS", "SS"},
{"SSS", "SSS"},
{"SSSS", "SSSS"},
{"jmsSSS", "h:mm:ss.SSS a"},
{"jmSSS", "h:mm:ss.SSS a"}
};
ULocale locale = ULocale.ENGLISH;
for (String[] cas : cases) {
DateFormat fmt = DateFormat.getInstanceForSkeleton( cas[0], locale);
String pattern = ((SimpleDateFormat) fmt).toPattern();
assertEquals("Format pattern", cas[1], pattern);
}
}
}