ICU-20739 Force seconds if the skeleton has fractional seconds

diff --git a/icu4c/source/i18n/dtptngen.cpp b/icu4c/source/i18n/dtptngen.cpp
index c5f8618..4948d2c 100644
--- a/icu4c/source/i18n/dtptngen.cpp
+++ b/icu4c/source/i18n/dtptngen.cpp
@@ -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) {
diff --git a/icu4c/source/test/intltest/dtfmttst.cpp b/icu4c/source/test/intltest/dtfmttst.cpp
index 9684e88..46f4be2 100644
--- a/icu4c/source/test/intltest/dtfmttst.cpp
+++ b/icu4c/source/test/intltest/dtfmttst.cpp
@@ -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++) {
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/DateTimePatternGenerator.java b/icu4j/main/classes/core/src/com/ibm/icu/text/DateTimePatternGenerator.java
index 70c136c..eb23318 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/text/DateTimePatternGenerator.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/text/DateTimePatternGenerator.java
@@ -2649,6 +2649,25 @@ DateTimeMatcher set(String pattern, FormatParser fp, boolean allowDuplicateField
                 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') {
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java
index f2e3849..735d45d 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatTest.java
@@ -5431,4 +5431,31 @@ public void TestParseRegression13744() {
         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);
+        }
+    }
 }