Skip to content

Commit

Permalink
ICU-21984 Fix DateIntervalFormat.normalizeHourMetacharacters() so tha…
Browse files Browse the repository at this point in the history
…t it doesn't require the hour and day-period

fields to appear in any particular order or position in the skeleton string.
  • Loading branch information
richgillam committed Apr 11, 2022
1 parent 4747484 commit 87cee86
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 59 deletions.
57 changes: 28 additions & 29 deletions icu4c/source/i18n/dtitvfmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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;
}
result.replace(metacharStart, metacharCount, hourAndDayPeriod);
for (int32_t i = 0; i < newDayPeriodLength; i++) {
hourAndDayPeriod.append(dayPeriodChar);
}
}
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;
}
Expand Down
4 changes: 4 additions & 0 deletions icu4c/source/test/intltest/dtifmtts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1616,23 +1616,26 @@ private String normalizeHourMetacharacters(String skeleton, ULocale locale) {

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;
}
}
Expand Down Expand Up @@ -1671,32 +1674,26 @@ private String normalizeHourMetacharacters(String skeleton, ULocale locale) {
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;
}
result.replace(metacharStart, metacharStart + metacharCount, hourAndDayPeriod.toString());
for (int i = 0; i < newDayPeriodLength; i++) {
hourAndDayPeriod.append(dayPeriodChar);
}
}
result.replace(hourFieldStart, hourFieldStart + hourFieldLength, hourAndDayPeriod.toString());
if (dayPeriodStart > hourFieldStart) {
dayPeriodStart += hourAndDayPeriod.length() - hourFieldLength;
}
result.delete(dayPeriodStart, dayPeriodStart + dayPeriodLength);
}
return result.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,10 @@ public void 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, DATA.length);
}
Expand Down

0 comments on commit 87cee86

Please sign in to comment.