ICU-21984 Fix DateIntervalFormat.normalizeHourMetacharacters() so that it doesn't require the hour and day-period

fields to appear in any particular order or position in the skeleton string.
This commit is contained in:
Rich Gillam 2022-04-13 17:06:52 -07:00 committed by Peter Edberg
parent c205e7ee49
commit 131146a5f4
4 changed files with 63 additions and 59 deletions

View file

@ -966,23 +966,26 @@ DateIntervalFormat::normalizeHourMetacharacters(const UnicodeString& skeleton) c
UChar hourMetachar = u'\0';
UChar dayPeriodChar = u'\0';
int32_t metacharStart = 0;
int32_t metacharCount = 0;
int32_t hourFieldStart = 0;
int32_t hourFieldLength = 0;
int32_t dayPeriodStart = 0;
int32_t dayPeriodLength = 0;
for (int32_t i = 0; i < result.length(); i++) {
UChar c = result[i];
if (c == LOW_J || c == CAP_J || c == CAP_C || c == LOW_H || c == CAP_H || c == LOW_K || c == CAP_K) {
if (hourMetachar == u'\0') {
hourMetachar = c;
metacharStart = i;
hourFieldStart = i;
}
++metacharCount;
++hourFieldLength;
} else if (c == LOW_A || c == LOW_B || c == CAP_B) {
if (dayPeriodChar == u'\0') {
dayPeriodChar = c;
dayPeriodStart = i;
}
++metacharCount;
++dayPeriodLength;
} else {
if (hourMetachar != u'\0') {
if (hourMetachar != u'\0' && dayPeriodChar != u'\0') {
break;
}
}
@ -1022,31 +1025,27 @@ DateIntervalFormat::normalizeHourMetacharacters(const UnicodeString& skeleton) c
}
}
if (hourChar == CAP_H || hourChar == LOW_K) {
result.replace(metacharStart, metacharCount, hourChar);
} else {
UnicodeString hourAndDayPeriod(hourChar);
switch (metacharCount) {
case 1:
case 2:
default:
hourAndDayPeriod.append(UnicodeString(dayPeriodChar));
break;
case 3:
case 4:
for (int32_t i = 0; i < 4; i++) {
hourAndDayPeriod.append(dayPeriodChar);
}
break;
case 5:
case 6:
for (int32_t i = 0; i < 5; i++) {
hourAndDayPeriod.append(dayPeriodChar);
}
break;
UnicodeString hourAndDayPeriod(hourChar);
if (hourChar != CAP_H && hourChar != LOW_K) {
int32_t newDayPeriodLength = 0;
if (dayPeriodLength >= 5 || hourFieldLength >= 5) {
newDayPeriodLength = 5;
} else if (dayPeriodLength >= 3 || hourFieldLength >= 3) {
newDayPeriodLength = 3;
} else {
newDayPeriodLength = 1;
}
for (int32_t i = 0; i < newDayPeriodLength; i++) {
hourAndDayPeriod.append(dayPeriodChar);
}
result.replace(metacharStart, metacharCount, hourAndDayPeriod);
}
result.replace(hourFieldStart, hourFieldLength, hourAndDayPeriod);
if (dayPeriodStart > hourFieldStart) {
// before deleting the original day period field, adjust its position in case
// we just changed the size of the hour field (and new day period field)
dayPeriodStart += hourAndDayPeriod.length() - hourFieldLength;
}
result.remove(dayPeriodStart, dayPeriodLength);
}
return result;
}

View file

@ -1194,6 +1194,10 @@ void DateIntervalFormatTest::testHourMetacharacters() {
"en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "KK", "12 \\u2013 1 AM", // (this was producing "0 - 1 AM" before)
"en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 00:00:00", "jj", "12 AM",
"en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "jj", "12 \\u2013 1 AM",
// regression test for ICU-21984 (multiple day-period characters in date-interval patterns)
"en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "MMMdhhmma", "Sep 27, 12:00 \\u2013 1:00 AM",
"sq", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "Bhm", "12:00 \\u2013 1:00 e nat\\u00EBs",
};
expect(DATA, UPRV_LENGTHOF(DATA));
}

View file

@ -1616,23 +1616,26 @@ public class DateIntervalFormat extends UFormat {
char hourMetachar = '\0';
char dayPeriodChar = '\0';
int metacharStart = 0;
int metacharCount = 0;
int hourFieldStart = 0;
int hourFieldLength = 0;
int dayPeriodStart = 0;
int dayPeriodLength = 0;
for (int i = 0; i < result.length(); i++) {
char c = result.charAt(i);
if (c == 'j' || c == 'J' || c == 'C' || c == 'h' || c == 'H' || c == 'k' || c == 'K') {
if (hourMetachar == '\0') {
hourMetachar = c;
metacharStart = i;
hourFieldStart = i;
}
++metacharCount;
++hourFieldLength;
} else if (c == 'a' || c == 'b' || c == 'B') {
if (dayPeriodChar == '\0') {
dayPeriodChar = c;
dayPeriodStart = i;
}
++metacharCount;
++dayPeriodLength;
} else {
if (hourMetachar != '\0') {
if (hourMetachar != '\0' && dayPeriodChar != '\0') {
break;
}
}
@ -1671,32 +1674,26 @@ public class DateIntervalFormat extends UFormat {
dayPeriodChar = 'a';
}
if (hourChar == 'H' || hourChar == 'k') {
result.replace(metacharStart, metacharStart + metacharCount, String.valueOf(hourChar));
} else {
StringBuilder hourAndDayPeriod = new StringBuilder();
hourAndDayPeriod.append(hourChar);
switch (metacharCount) {
case 1:
case 2:
default:
hourAndDayPeriod.append(dayPeriodChar);
break;
case 3:
case 4:
for (int i = 0; i < 4; i++) {
hourAndDayPeriod.append(dayPeriodChar);
}
break;
case 5:
case 6:
for (int i = 0; i < 5; i++) {
hourAndDayPeriod.append(dayPeriodChar);
}
break;
StringBuilder hourAndDayPeriod = new StringBuilder();
hourAndDayPeriod.append(hourChar);
if (hourChar != 'H' && hourChar != 'k') {
int newDayPeriodLength = 0;
if (dayPeriodLength >= 5 || hourFieldLength >= 5) {
newDayPeriodLength = 5;
} else if (dayPeriodLength >= 3 || hourFieldLength >= 3) {
newDayPeriodLength = 3;
} else {
newDayPeriodLength = 1;
}
for (int i = 0; i < newDayPeriodLength; i++) {
hourAndDayPeriod.append(dayPeriodChar);
}
result.replace(metacharStart, metacharStart + metacharCount, hourAndDayPeriod.toString());
}
result.replace(hourFieldStart, hourFieldStart + hourFieldLength, hourAndDayPeriod.toString());
if (dayPeriodStart > hourFieldStart) {
dayPeriodStart += hourAndDayPeriod.length() - hourFieldLength;
}
result.delete(dayPeriodStart, dayPeriodStart + dayPeriodLength);
}
return result.toString();
}

View file

@ -839,6 +839,10 @@ public class DateIntervalFormatTest extends TestFmwk {
"en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "KK", "12 \\u2013 1 AM", // (this was producing "0 - 1 AM" before)
"en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 00:00:00", "jj", "12 AM",
"en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "jj", "12 \\u2013 1 AM",
// regression test for ICU-21984 (multiple day-period characters in date-interval patterns)
"en", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "MMMdhhmma", "Sep 27, 12:00 \\u2013 1:00 AM",
"sq", "CE 2010 09 27 00:00:00", "CE 2010 09 27 01:00:00", "Bhm", "12:00 \\u2013 1:00 e nat\\u00EBs",
};
expect(DATA, DATA.length);
}