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/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));
 }