Cherrypick PR 2060 to fix DateIntervalFormat
This is a regression in 71-1 on DateIntervalFormat
https://github.com/unicode-org/icu/pull/2060
https://unicode-org.atlassian.net/browse/ICU-21984
Bug: 1316665
Change-Id: Icd3b9e329ffd993457e1c2f0b86ed178f4a7b259
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/deps/icu/+/3587906
Reviewed-by: Jungshik Shin <jshin@chromium.org>
diff --git a/README.chromium b/README.chromium
index 15973b5..d5ba188 100644
--- a/README.chromium
+++ b/README.chromium
@@ -248,3 +248,8 @@
9. Patch source/common/uposixdefs.h so it compiles on Fuchsia on Macs.
patches/fuchsia.patch
- context bug: https://bugs.chromium.org/p/chromium/issues/detail?id=1184527
+
+10. Patch i18n/dtitvfmt.cpp to fix DateIntervalFormat regression
+ patches/DateIntervalFormatnormalizeHourMetacharacters.patch
+ - https://github.com/unicode-org/icu/pull/2060
+ - https://unicode-org.atlassian.net/browse/ICU-21984
diff --git a/patches/DateIntervalFormatnormalizeHourMetacharacters.patch b/patches/DateIntervalFormatnormalizeHourMetacharacters.patch
new file mode 100644
index 0000000..f40ee47
--- /dev/null
+++ b/patches/DateIntervalFormatnormalizeHourMetacharacters.patch
@@ -0,0 +1,103 @@
+diff --git a/source/i18n/dtitvfmt.cpp b/source/i18n/dtitvfmt.cpp
+index d51ddcd5..df9d23bd 100644
+--- a/source/i18n/dtitvfmt.cpp
++++ b/source/i18n/dtitvfmt.cpp
+@@ -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;
+ }
+- 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;
+ }
+diff --git a/source/test/intltest/dtifmtts.cpp b/source/test/intltest/dtifmtts.cpp
+index 605eae43..f2774433 100644
+--- a/source/test/intltest/dtifmtts.cpp
++++ b/source/test/intltest/dtifmtts.cpp
+@@ -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));
+ }
diff --git a/source/i18n/dtitvfmt.cpp b/source/i18n/dtitvfmt.cpp
index d51ddcd..df9d23b 100644
--- a/source/i18n/dtitvfmt.cpp
+++ b/source/i18n/dtitvfmt.cpp
@@ -966,23 +966,26 @@
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 @@
}
}
- 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;
}
diff --git a/source/test/intltest/dtifmtts.cpp b/source/test/intltest/dtifmtts.cpp
index 605eae4..f277443 100644
--- a/source/test/intltest/dtifmtts.cpp
+++ b/source/test/intltest/dtifmtts.cpp
@@ -1194,6 +1194,10 @@
"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));
}