ICU-12902 make create/getInstanceForSkeleton use correct calendar; don't try to capitalize empty field
diff --git a/icu4c/source/i18n/datefmt.cpp b/icu4c/source/i18n/datefmt.cpp
index e8641f4..76ec3f4 100644
--- a/icu4c/source/i18n/datefmt.cpp
+++ b/icu4c/source/i18n/datefmt.cpp
@@ -460,7 +460,12 @@
         status = U_ILLEGAL_ARGUMENT_ERROR;
         return NULL;
     }
-    DateFormat *result = createInstanceForSkeleton(skeleton, locale, status);
+    Locale localeWithCalendar = locale;
+    localeWithCalendar.setKeywordValue("calendar", calendar->getType(), status);
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+    DateFormat *result = createInstanceForSkeleton(skeleton, localeWithCalendar, status);
     if (U_FAILURE(status)) {
         return NULL;
     }
diff --git a/icu4c/source/i18n/smpdtfmt.cpp b/icu4c/source/i18n/smpdtfmt.cpp
index 8a95a02..b691944 100644
--- a/icu4c/source/i18n/smpdtfmt.cpp
+++ b/icu4c/source/i18n/smpdtfmt.cpp
@@ -1950,7 +1950,8 @@
     }
 #if !UCONFIG_NO_BREAK_ITERATION
     // if first field, check to see whether we need to and are able to titlecase it
-    if (fieldNum == 0 && u_islower(appendTo.char32At(beginOffset)) && fCapitalizationBrkIter != NULL) {
+    if (fieldNum == 0 && fCapitalizationBrkIter != NULL && appendTo.length() > beginOffset &&
+            u_islower(appendTo.char32At(beginOffset))) {
         UBool titlecase = FALSE;
         switch (capitalizationContext) {
             case UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE:
diff --git a/icu4c/source/test/intltest/dtfmrgts.cpp b/icu4c/source/test/intltest/dtfmrgts.cpp
index 260f8fa..5e04379 100644
--- a/icu4c/source/test/intltest/dtfmrgts.cpp
+++ b/icu4c/source/test/intltest/dtfmrgts.cpp
@@ -59,11 +59,12 @@
         CASE(26,Test5554)
         CASE(27,Test9237)
         CASE(28,TestParsing)
-        CASE(29,TestT10334)
-        CASE(30,TestT10619)
-        CASE(31,TestT10855)
-        CASE(32,TestT10906)
-        CASE(33,TestT13380)
+        CASE(29,Test12902_yWithGregoCalInThaiLoc)
+        CASE(30,TestT10334)
+        CASE(31,TestT10619)
+        CASE(32,TestT10855)
+        CASE(33,TestT10906)
+        CASE(34,TestT13380)
         default: name = ""; break;
     }
 }
@@ -1533,6 +1534,55 @@
     delete cal;
 }
 
+void DateFormatRegressionTest::Test12902_yWithGregoCalInThaiLoc(void) {
+    UErrorCode status = U_ZERO_ERROR;
+    UDate testDate = 43200000.0; // 1970-Jan-01 12:00 GMT
+    const char* skeleton = "y";
+    // Note that in locale "th", the availableFormats for skeleton "y" differ by calendar:
+    // for buddhist (default calendar): y{"G y"}
+    // for gregorian: y{"y"}
+    const char* expectFormat = "1970"; // format for skeleton y in Thai locale with Gregorian calendar
+    UnicodeString getFmtStr;
+
+    const TimeZone* gmtZone = TimeZone::getGMT();
+    LocalPointer<GregorianCalendar> pureGregoCal(new GregorianCalendar(*gmtZone, Locale::getEnglish(), status));
+    if (U_FAILURE(status)) {
+        dataerrln("Fail in new GregorianCalendar(GMT, en): %s", u_errorName(status));
+        return;
+    }
+    LocalPointer<DateFormat> df1(DateFormat::createInstanceForSkeleton(pureGregoCal.orphan(), skeleton, "th", status));
+    if (U_FAILURE(status)) {
+        dataerrln("Fail in DateFormat::createInstanceForSkeleton for th with Grego cal: %s", u_errorName(status));
+        return;
+    }
+    status = U_ZERO_ERROR;
+    getFmtStr.remove();
+    getFmtStr = df1->format(testDate, getFmtStr);
+    if (U_FAILURE(status)) {
+        errln("Fail in DateFormat::format for th with Grego cal: %s", u_errorName(status));
+    } else if (getFmtStr != expectFormat) {
+        char getFormat[32];
+        getFmtStr.extract(0, getFmtStr.length(), getFormat, 32);
+        errln("Error in DateFormat::format for th with Grego cal, expect: %s, get: %s", expectFormat, getFormat);
+    }
+
+    LocalPointer<DateFormat> df2(DateFormat::createInstanceForSkeleton(skeleton, "th-u-ca-gregory", status));
+    if (U_FAILURE(status)) {
+        dataerrln("Fail in DateFormat::createInstanceForSkeleton for th-u-ca-gregory: %s", u_errorName(status));
+        return;
+    }
+    status = U_ZERO_ERROR;
+    getFmtStr.remove();
+    getFmtStr = df2->format(testDate, getFmtStr);
+    if (U_FAILURE(status)) {
+        errln("Fail in DateFormat::format for th-u-ca-gregory: %s", u_errorName(status));
+    } else if (getFmtStr != expectFormat) {
+        char getFormat[32];
+        getFmtStr.extract(0, getFmtStr.length(), getFormat, 32);
+        errln("Error in DateFormat::format for th with Grego cal, expect: %s, get: %s", expectFormat, getFormat);
+    }
+}
+
 void DateFormatRegressionTest::TestT10334(void) {
     UErrorCode status = U_ZERO_ERROR;
     UnicodeString pattern("'--: 'EEE-WW-MMMM-yyyy");
diff --git a/icu4c/source/test/intltest/dtfmrgts.h b/icu4c/source/test/intltest/dtfmrgts.h
index be8dd0f..305487d 100644
--- a/icu4c/source/test/intltest/dtfmrgts.h
+++ b/icu4c/source/test/intltest/dtfmrgts.h
@@ -55,6 +55,7 @@
     void Test5554(void);
     void Test9237(void);
     void TestParsing(void);
+    void Test12902_yWithGregoCalInThaiLoc(void);
     void TestT10334(void);
     void TestT10619(void);
     void TestT10855(void);
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/DateFormat.java b/icu4j/main/classes/core/src/com/ibm/icu/text/DateFormat.java
index d149841..bbc1174 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/text/DateFormat.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/text/DateFormat.java
@@ -2196,6 +2196,9 @@
      */
     public final static DateFormat getInstanceForSkeleton(
         Calendar cal, String skeleton, ULocale locale) {
+        if (cal != null) {
+            locale = locale.setKeywordValue("calendar", cal.getType());
+        }
         DateTimePatternGenerator generator = DateTimePatternGenerator.getInstance(locale);
         final String bestPattern = generator.getBestPattern(skeleton);
         SimpleDateFormat format = new SimpleDateFormat(bestPattern, locale);
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java b/icu4j/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java
index 7cdedd7..c14c238 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java
@@ -2041,7 +2041,8 @@
             break;
         } // switch (patternCharIndex)
 
-        if (fieldNum == 0 && capitalizationContext != null && UCharacter.isLowerCase(buf.codePointAt(bufstart))) {
+        if (fieldNum == 0 && capitalizationContext != null && buf.length() > bufstart &&
+                UCharacter.isLowerCase(buf.codePointAt(bufstart))) {
             boolean titlecase = false;
             switch (capitalizationContext) {
                 case CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE:
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatRegressionTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatRegressionTest.java
index 350a9f4..83826ec 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatRegressionTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/DateFormatRegressionTest.java
@@ -1239,6 +1239,38 @@
     }
 
     @Test
+    public void Test12902_yWithGregoCalInThaiLoc() {
+        final Date testDate = new Date(43200000); // 1970-Jan-01 12:00 GMT
+        final String skeleton = "y";
+        // Note that in locale "th", the availableFormats for skeleton "y" differ by calendar:
+        // for buddhist (default calendar): y{"G y"}
+        // for gregorian: y{"y"}
+        final String expectFormat = "1970"; // format for skeleton y in Thai locale with Gregorian calendar
+
+        GregorianCalendar pureGregorianCalendar = new GregorianCalendar(TimeZone.GMT_ZONE, ULocale.ENGLISH);
+        pureGregorianCalendar.setGregorianChange(new Date(Long.MIN_VALUE)); // Per original bug, but not relevant
+        DateFormat df1 = DateFormat.getPatternInstance(pureGregorianCalendar, skeleton, ULocale.forLanguageTag("th"));
+        try {
+            String getFormat = df1.format(testDate);
+            if (!getFormat.equals(expectFormat)) {
+                errln("Error in DateFormat.format for th with Grego cal, expect: " + expectFormat + ", get: " + getFormat);
+            }
+        } catch (Exception e) {
+            errln("Fail in DateFormat.format for th with Grego cal: " + e);
+        }
+
+        DateFormat df2 = DateFormat.getPatternInstance(skeleton, new ULocale("th-u-ca-gregory"));
+        try {
+            String getFormat = df2.format(testDate);
+            if (!getFormat.equals(expectFormat)) {
+                errln("Error in DateFormat.format for th-u-ca-gregory, expect: " + expectFormat + ", get: " + getFormat);
+            }
+        } catch (Exception e) {
+            errln("Fail in DateFormat.format for th-u-ca-gregory: " + e);
+        }
+    }
+
+    @Test
     public void TestT10110() {
         try {
             SimpleDateFormat formatter = new SimpleDateFormat("Gy年M月d日E", new Locale("zh_Hans"));