]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/test/intltest/dtfmttst.cpp
ICU-59117.0.1.tar.gz
[apple/icu.git] / icuSources / test / intltest / dtfmttst.cpp
index 1c0083999e0330a9e02a58e4f346c7c4dbcab8da..676741a3974d73957205e4b1edee25fc3f4148e9 100644 (file)
@@ -1,6 +1,8 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /********************************************************************
  * COPYRIGHT:
- * Copyright (c) 1997-2015, International Business Machines
+ * Copyright (c) 1997-2016, International Business Machines
  * Corporation and others. All Rights Reserved.
  ********************************************************************/
 
 #include "caltest.h"  // for fieldName
 #include <stdio.h> // for sprintf
 
-#if U_PLATFORM_HAS_WIN32_API
+#if U_PLATFORM_USES_ONLY_WIN32_API
 #include "windttst.h"
 #endif
 
-#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
-
 #define ASSERT_OK(status)  if(U_FAILURE(status)) {errcheckln(status, #status " = %s @ %s:%d", u_errorName(status), __FILE__, __LINE__); return; }
 
 // *****************************************************************************
@@ -96,6 +96,7 @@ void DateFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &nam
     TESTCASE_AUTO(TestMonthPatterns);
     TESTCASE_AUTO(TestContext);
     TESTCASE_AUTO(TestNonGregoFmtParse);
+    TESTCASE_AUTO(TestFormatsWithNumberSystems);
     /*
     TESTCASE_AUTO(TestRelativeError);
     TESTCASE_AUTO(TestRelativeOther);
@@ -113,6 +114,14 @@ void DateFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &nam
     TESTCASE_AUTO(TestDFSCreateForLocaleWithCalendarInLocale);
     TESTCASE_AUTO(TestChangeCalendar);
 
+    TESTCASE_AUTO(TestPatternFromSkeleton);
+
+    TESTCASE_AUTO(TestAmPmMidnightNoon);
+    TESTCASE_AUTO(TestFlexibleDayPeriod);
+    TESTCASE_AUTO(TestDayPeriodWithLocales);
+    TESTCASE_AUTO(TestMinuteSecondFieldsInOddPlaces);
+    TESTCASE_AUTO(TestDayPeriodParsing);
+
     TESTCASE_AUTO_END;
 }
 
@@ -127,21 +136,21 @@ void DateFormatTest::TestPatterns() {
 
         {UDAT_QUARTER, "QQQQ", "en", "QQQQ"},
         {UDAT_ABBR_QUARTER, "QQQ", "en", "QQQ"},
-        {UDAT_YEAR_QUARTER, "yQQQQ", "en", "QQQQ y"}, 
+        {UDAT_YEAR_QUARTER, "yQQQQ", "en", "QQQQ y"},
         {UDAT_YEAR_ABBR_QUARTER, "yQQQ", "en", "QQQ y"},
 
         {UDAT_NUM_MONTH, "M", "en", "L"},
         {UDAT_ABBR_MONTH, "MMM", "en", "LLL"},
         {UDAT_MONTH, "MMMM", "en", "LLLL"},
-        {UDAT_YEAR_NUM_MONTH, "yM","en","M/y"}, 
+        {UDAT_YEAR_NUM_MONTH, "yM","en","M/y"},
         {UDAT_YEAR_ABBR_MONTH, "yMMM","en","MMM y"},
         {UDAT_YEAR_MONTH, "yMMMM","en","MMMM y"},
 
         {UDAT_DAY, "d","en","d"},
-        {UDAT_YEAR_NUM_MONTH_DAY, "yMd", "en", "M/d/y"}, 
+        {UDAT_YEAR_NUM_MONTH_DAY, "yMd", "en", "M/d/y"},
         {UDAT_YEAR_ABBR_MONTH_DAY, "yMMMd", "en", "MMM d, y"},
         {UDAT_YEAR_MONTH_DAY, "yMMMMd", "en", "MMMM d, y"},
-        {UDAT_YEAR_NUM_MONTH_WEEKDAY_DAY, "yMEd", "en", "EEE, M/d/y"}, 
+        {UDAT_YEAR_NUM_MONTH_WEEKDAY_DAY, "yMEd", "en", "EEE, M/d/y"},
         {UDAT_YEAR_ABBR_MONTH_WEEKDAY_DAY, "yMMMEd", "en", "EEE, MMM d, y"},
         {UDAT_YEAR_MONTH_WEEKDAY_DAY, "yMMMMEEEEd", "en", "EEEE, MMMM d, y"},
 
@@ -182,15 +191,15 @@ void DateFormatTest::TestPatterns() {
         UnicodeString expectedPattern(EXPECTED[i].expectedPattern, -1, US_INV);
         Locale locale(EXPECTED[i].localeID);
         if (actualPattern != expectedPattern) {
-            errln("FAILURE! Expected pattern: " + expectedPattern + 
+            errln("FAILURE! Expected pattern: " + expectedPattern +
                     " but was: " + actualPattern);
         }
 
-        // Verify that DataFormat instances produced contain the correct 
+        // Verify that DataFormat instances produced contain the correct
         // localized patterns
         // TODO: use DateFormat::getInstanceForSkeleton(), ticket #9029
         // Java test code:
-        // DateFormat date1 = DateFormat.getPatternInstance(actualPattern, 
+        // DateFormat date1 = DateFormat.getPatternInstance(actualPattern,
         //         locale);
         // DateFormat date2 = DateFormat.getPatternInstance(Calendar.getInstance(locale),
         //         actualPattern, locale);
@@ -215,11 +224,11 @@ void DateFormatTest::TestPatterns() {
         date1.toLocalizedPattern(actualLocalPattern1, errorCode);
         date2.toLocalizedPattern(actualLocalPattern2, errorCode);
         if (actualLocalPattern1 != expectedLocalPattern) {
-            errln("FAILURE! Expected local pattern: " + expectedLocalPattern 
+            errln("FAILURE! Expected local pattern: " + expectedLocalPattern
                     + " but was: " + actualLocalPattern1);
         }
         if (actualLocalPattern2 != expectedLocalPattern) {
-            errln("FAILURE! Expected local pattern: " + expectedLocalPattern 
+            errln("FAILURE! Expected local pattern: " + expectedLocalPattern
                     + " but was: " + actualLocalPattern2);
         }
     }
@@ -298,7 +307,7 @@ void DateFormatTest::TestWallyWedel()
          * Format the output.
          */
         UnicodeString fmtOffset;
-        FieldPosition pos(0);
+        FieldPosition pos(FieldPosition::DONT_CARE);
         sdf->format(today,fmtOffset, pos);
         // UnicodeString fmtOffset = tzS.toString();
         UnicodeString *fmtDstOffset = 0;
@@ -433,7 +442,11 @@ DateFormatTest::escape(UnicodeString& s)
 /**
  * This MUST be kept in sync with DateFormatSymbols.gPatternChars.
  */
-static const char* PATTERN_CHARS = "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxr:";
+#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
+static const char* PATTERN_CHARS = "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB:";
+#else
+static const char* PATTERN_CHARS = "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxrbB";
+#endif
 
 /**
  * A list of the names of all the fields in DateFormat.
@@ -475,11 +488,13 @@ static const char* DATEFORMAT_FIELD_NAMES[] = {
     "TIMEZONE_ISO_FIELD",
     "TIMEZONE_ISO_LOCAL_FIELD",
     "RELATED_YEAR_FIELD",
+    "AM_PM_MIDNIGHT_NOON_FIELD",
+    "FLEXIBLE_DAY_PERIOD_FIELD",
     "UDAT_TIME_SEPARATOR_FIELD",
 };
 
 static const int32_t DATEFORMAT_FIELD_NAMES_LENGTH =
-    sizeof(DATEFORMAT_FIELD_NAMES) / sizeof(DATEFORMAT_FIELD_NAMES[0]);
+    UPRV_LENGTHOF(DATEFORMAT_FIELD_NAMES);
 
 /**
  * Verify that returned field position indices are correct.
@@ -501,7 +516,11 @@ void DateFormatTest::TestFieldPosition() {
     assertEquals("patternChars", PATTERN_CHARS, rootSyms.getLocalPatternChars(buf));
     assertEquals("patternChars", PATTERN_CHARS, DateFormatSymbols::getPatternUChars());
     assertTrue("DATEFORMAT_FIELD_NAMES", DATEFORMAT_FIELD_NAMES_LENGTH == UDAT_FIELD_COUNT);
+#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
     assertTrue("Data", UDAT_FIELD_COUNT == uprv_strlen(PATTERN_CHARS));
+#else
+    assertTrue("Data", UDAT_FIELD_COUNT == uprv_strlen(PATTERN_CHARS) + 1); // +1 for missing TIME_SEPARATOR pattern char
+#endif
 
     // Create test formatters
     const int32_t COUNT = 4;
@@ -530,26 +549,44 @@ void DateFormatTest::TestFieldPosition() {
     const char* EXPECTED[] = {
         "", "1997", "August", "13", "", "", "34", "12", "", "Wednesday",
         "", "", "", "", "PM", "2", "", "Pacific Daylight Time", "", "",
-        "", "", "", "", "", "", "", "", "", "",
-        "", "", "", "", "", ":",
+        "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
+        ":",
+#else
+        "",
+#endif
 
         "", "1997", "ao\\u00FBt", "13", "", "14", "34", "12", "", "mercredi",
         "", "", "", "", "", "", "", "heure d\\u2019\\u00E9t\\u00E9 du Pacifique", "", "",
-        "", "", "", "", "",  "", "", "", "", "",
-        "", "", "", "", "", ":",
+        "", "", "", "", "",  "", "", "", "", "", "", "", "", "", "", "", "",
+#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
+        ":",
+#else
+        "",
+#endif
 
         "AD", "1997", "8", "13", "14", "14", "34", "12", "5", "Wed",
         "225", "2", "33", "3", "PM", "2", "2", "PDT", "1997", "4",
         "1997", "2450674", "52452513", "-0700", "PT",  "4", "8", "3", "3", "uslax",
-        "1997", "GMT-7", "-07", "-07", "1997", ":",
+        "1997", "GMT-7", "-07", "-07", "1997", "PM", "in the afternoon",
+#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
+        ":",
+#else
+        "",
+#endif
 
         "Anno Domini", "1997", "August", "0013", "0014", "0014", "0034", "0012", "5130", "Wednesday",
         "0225", "0002", "0033", "0003", "PM", "0002", "0002", "Pacific Daylight Time", "1997", "Wednesday",
         "1997", "2450674", "52452513", "GMT-07:00", "Pacific Time",  "Wednesday", "August", "3rd quarter", "3rd quarter", "Los Angeles Time",
-        "1997", "GMT-07:00", "-0700", "-0700", "1997", ":",
+        "1997", "GMT-07:00", "-0700", "-0700", "1997", "PM", "in the afternoon",
+#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
+        ":",
+#else
+        "",
+#endif
     };
 
-    const int32_t EXPECTED_LENGTH = sizeof(EXPECTED)/sizeof(EXPECTED[0]);
+    const int32_t EXPECTED_LENGTH = UPRV_LENGTHOF(EXPECTED);
 
     assertTrue("data size", EXPECTED_LENGTH == COUNT * UDAT_FIELD_COUNT);
 
@@ -625,7 +662,7 @@ void DateFormatTest::TestGeneral() {
         "y/M/d H:mm:ss.SSS", "F", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.567",
         "y/M/d H:mm:ss.SSSS", "pf", "2004/3/10 16:36:31.5679", "2004 03 10 16:36:31.567", "2004/3/10 16:36:31.5670",
     };
-    expect(DATA, ARRAY_SIZE(DATA), Locale("en", "", ""));
+    expect(DATA, UPRV_LENGTHOF(DATA), Locale("en", "", ""));
 }
 
 // -------------------------------------
@@ -942,11 +979,11 @@ DateFormatTest::TestBadInput135()
     DateFormat::EStyle looks[] = {
         DateFormat::SHORT, DateFormat::MEDIUM, DateFormat::LONG, DateFormat::FULL
     };
-    int32_t looks_length = (int32_t)(sizeof(looks) / sizeof(looks[0]));
+    int32_t looks_length = UPRV_LENGTHOF(looks);
     const char* strings[] = {
         "Mar 15", "Mar 15 1997", "asdf", "3/1/97 1:23:", "3/1/00 1:23:45 AM"
     };
-    int32_t strings_length = (int32_t)(sizeof(strings) / sizeof(strings[0]));
+    int32_t strings_length = UPRV_LENGTHOF(strings);
     DateFormat *full = DateFormat::createDateTimeInstance(DateFormat::LONG, DateFormat::LONG);
     if(full==NULL) {
       dataerrln("could not create date time instance");
@@ -1044,7 +1081,7 @@ static const char* const inputStrings[] = {
     "3:00 pm Jan 1, 1997", 0, 0, 0, 0, 0, 0, 0, "0003", "3:00 PM January 1, 1997",
 };
 #endif
+
 // -------------------------------------
 
 /**
@@ -1064,8 +1101,8 @@ DateFormatTest::TestBadInput135a()
   }
   const char* s;
   UDate date;
-  const uint32_t PF_LENGTH = (int32_t)(sizeof(parseFormats)/sizeof(parseFormats[0]));
-  const uint32_t INPUT_LENGTH = (int32_t)(sizeof(inputStrings)/sizeof(inputStrings[0]));
+  const uint32_t PF_LENGTH = UPRV_LENGTHOF(parseFormats);
+  const uint32_t INPUT_LENGTH = UPRV_LENGTHOF(inputStrings);
 
   dateParse->applyPattern("d MMMM, yyyy");
   dateParse->adoptTimeZone(TimeZone::createDefault());
@@ -1249,7 +1286,7 @@ DateFormatTest::TestDateFormatZone146()
                 UnicodeString("short format:   "), UnicodeString("4/4/97 11:00 PM"),
                     UnicodeString("M/d/yy h:mm a")
             };
-            int32_t DATA_length = (int32_t)(sizeof(DATA) / sizeof(DATA[0]));
+            int32_t DATA_length = UPRV_LENGTHOF(DATA);
 
             for (int32_t i=0; i<DATA_length; i+=3) {
                 DateFormat *fmt = new SimpleDateFormat(DATA[i+2], Locale::getEnglish(), status);
@@ -1290,7 +1327,7 @@ DateFormatTest::TestLocaleDateFormat() // Bug 495
         DateFormat::FULL, Locale::getFrench());
     DateFormat *dfUS = DateFormat::createDateTimeInstance(DateFormat::FULL,
         DateFormat::FULL, Locale::getUS());
-    UnicodeString expectedFRENCH ( "lundi 15 septembre 1997 00:00:00 heure d\\u2019\\u00E9t\\u00E9 du Pacifique", -1, US_INV );
+    UnicodeString expectedFRENCH ( "lundi 15 septembre 1997 \\u00E0 00:00:00 heure d\\u2019\\u00E9t\\u00E9 du Pacifique", -1, US_INV );
     expectedFRENCH = expectedFRENCH.unescape();
     UnicodeString expectedUS ( "Monday, September 15, 1997 at 12:00:00 AM Pacific Daylight Time" );
     logln((UnicodeString)"Date set to : " + dateToString(testDate));
@@ -1318,6 +1355,8 @@ DateFormatTest::TestLocaleDateFormat() // Bug 495
 void
 DateFormatTest::TestFormattingLocaleTimeSeparator()
 {
+    // This test not as useful is it once was, since timeSeparator
+    // in the Arabic is changed back to ":" in CLDR 28.
     const UDate testDate = 874266720000.;  // Sun Sep 14 21:52:00 CET 1997
     logln((UnicodeString)"Date set to : " + dateToString(testDate));
 
@@ -1338,10 +1377,10 @@ DateFormatTest::TestFormattingLocaleTimeSeparator()
     dfLatn->setTimeZone(*tz);
 
     const UnicodeString expectedArab = UnicodeString(
-            "\\u0669:\\u0665\\u0662 \\u0645", -1, US_INV).unescape();
+            "\\u0669:\\u0665\\u0662\\u00A0\\u0645", -1, US_INV).unescape();
 
     const UnicodeString expectedLatn = UnicodeString(
-            "9:52 \\u0645", -1, US_INV).unescape();
+            "9:52\\u00A0\\u0645", -1, US_INV).unescape();
 
     UnicodeString actualArab;
     UnicodeString actualLatn;
@@ -1466,18 +1505,18 @@ void DateFormatTest::TestSpaceParsing() {
         NULL,         "12:34:56PM",  "1970 01 01 12:34:56",
         NULL,         "12.34.56PM",  "1970 01 01 12:34:56",
         NULL,         "12 : 34 : 56  PM", "1970 01 01 12:34:56",
-        
+
         "MM d yy 'at' hh:mm:ss a", "04/05/06 12:34:56 PM", "2006 04 05 12:34:56",
-        
+
         "MMMM dd yyyy hh:mm a", "September 27, 1964 21:56 PM", "1964 09 28 09:56:00",
         NULL,                   "November 4, 2008 0:13 AM",    "2008 11 04 00:13:00",
-        
+
         "HH'h'mm'min'ss's'", "12h34min56s", "1970 01 01 12:34:56",
         NULL,                "12h34mi56s",  "1970 01 01 12:34:56",
         NULL,                "12h34m56s",   "1970 01 01 12:34:56",
         NULL,                "12:34:56",    "1970 01 01 12:34:56"
     };
-    const int32_t DATA_len = sizeof(DATA)/sizeof(DATA[0]);
+    const int32_t DATA_len = UPRV_LENGTHOF(DATA);
 
     expectParse(DATA, DATA_len, Locale("en"));
 }
@@ -1498,7 +1537,7 @@ void DateFormatTest::TestExactCountFormat() {
         NULL,     "00+05",  NULL,
         "ahhmm",  "PM730",  "1970 01 01 19:30:00",
     };
-    const int32_t DATA_len = sizeof(DATA)/sizeof(DATA[0]);
+    const int32_t DATA_len = UPRV_LENGTHOF(DATA);
 
     expectParse(DATA, DATA_len, Locale("en"));
 }
@@ -1516,7 +1555,7 @@ void DateFormatTest::TestWhiteSpaceParsing() {
         "MM   d yy",   " 04 01 03",    "2003 04 01",
         NULL,          " 04  01   03 ", "2003 04 01",
     };
-    const int32_t DATA_len = sizeof(DATA)/sizeof(DATA[0]);
+    const int32_t DATA_len = UPRV_LENGTHOF(DATA);
 
     expectParse(DATA, DATA_len, Locale("en"));
 }
@@ -1629,8 +1668,8 @@ void DateFormatTest::TestStandAloneMonths()
         "LLL", "fp", "1970 12 01 0:00:00", "pro", "1970 12 01 0:00:00",
     };
 
-    expect(EN_DATA, ARRAY_SIZE(EN_DATA), Locale("en", "", ""));
-    expect(CS_DATA, ARRAY_SIZE(CS_DATA), Locale("cs", "", ""));
+    expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
+    expect(CS_DATA, UPRV_LENGTHOF(CS_DATA), Locale("cs", "", ""));
 }
 
 void DateFormatTest::TestStandAloneDays()
@@ -1675,8 +1714,8 @@ void DateFormatTest::TestStandAloneDays()
         "ccc", "fp", "1970 01 03 0:00:00", "so",      "1970 01 03 0:00:00",
     };
 
-    expect(EN_DATA, ARRAY_SIZE(EN_DATA), Locale("en", "", ""));
-    expect(CS_DATA, ARRAY_SIZE(CS_DATA), Locale("cs", "", ""));
+    expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
+    expect(CS_DATA, UPRV_LENGTHOF(CS_DATA), Locale("cs", "", ""));
 }
 
 void DateFormatTest::TestShortDays()
@@ -1696,11 +1735,11 @@ void DateFormatTest::TestShortDays()
         "EEEEEE d MMM y",  "fp", "2013 01 13 0:00:00", "s\\u00F6 13 jan. 2013", "2013 01 13 0:00:00",
         "EEEEEE d MMM y",  "fp", "2013 01 16 0:00:00", "on 16 jan. 2013",       "2013 01 16 0:00:00",
         "EEEEEE d",        "fp", "1970 01 17 0:00:00", "l\\u00F6 17",          "1970 01 17 0:00:00",
-        "cccccc d",        "fp", "1970 01 17 0:00:00", "L\\u00F6 17",          "1970 01 17 0:00:00",
-        "cccccc",          "fp", "1970 01 03 0:00:00", "L\\u00F6",             "1970 01 03 0:00:00",
+        "cccccc d",        "fp", "1970 01 17 0:00:00", "l\\u00F6 17",          "1970 01 17 0:00:00",
+        "cccccc",          "fp", "1970 01 03 0:00:00", "l\\u00F6",             "1970 01 03 0:00:00",
     };
-    expect(EN_DATA, ARRAY_SIZE(EN_DATA), Locale("en", "", ""));
-    expect(SV_DATA, ARRAY_SIZE(SV_DATA), Locale("sv", "", ""));
+    expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
+    expect(SV_DATA, UPRV_LENGTHOF(SV_DATA), Locale("sv", "", ""));
 }
 
 void DateFormatTest::TestNarrowNames()
@@ -1752,7 +1791,7 @@ void DateFormatTest::TestNarrowNames()
             "ccccc", "1970 01 01 0:00:00", "T",
             "ccccc", "1970 01 02 0:00:00", "F",
             "ccccc", "1970 01 03 0:00:00", "S",
-            
+
             "h:mm a",     "2015 01 01 10:00:00", "10:00 AM",
             "h:mm a",     "2015 01 01 22:00:00", "10:00 PM",
             "h:mm aaaaa", "2015 01 01 10:00:00", "10:00 a",
@@ -1806,9 +1845,9 @@ void DateFormatTest::TestNarrowNames()
             "ccccc", "1970 01 01 0:00:00", "\\u010C",
             "ccccc", "1970 01 02 0:00:00", "P",
             "ccccc", "1970 01 03 0:00:00", "S",
-            
-            "h:mm a",     "2015 01 01 10:00:00", "10:00 dopoledne",
-            "h:mm a",     "2015 01 01 22:00:00", "10:00 odpoledne",
+
+            "h:mm a",     "2015 01 01 10:00:00", "10:00 dop.",
+            "h:mm a",     "2015 01 01 22:00:00", "10:00 odp.",
             "h:mm aaaaa", "2015 01 01 10:00:00", "10:00 dop.",
             "h:mm aaaaa", "2015 01 01 22:00:00", "10:00 odp.",
         };
@@ -1822,9 +1861,9 @@ void DateFormatTest::TestNarrowNames()
             "h:mm aaaaa", "2015 01 01 22:00:00", "10:00 p.m.",
         };
 
-      expectFormat(EN_DATA, ARRAY_SIZE(EN_DATA), Locale("en", "", ""));
-      expectFormat(CS_DATA, ARRAY_SIZE(CS_DATA), Locale("cs", "", ""));
-      expectFormat(CA_DATA, ARRAY_SIZE(CA_DATA), Locale("ca", "", ""));
+      expectFormat(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
+      expectFormat(CS_DATA, UPRV_LENGTHOF(CS_DATA), Locale("cs", "", ""));
+      expectFormat(CA_DATA, UPRV_LENGTHOF(CA_DATA), Locale("ca", "", ""));
 }
 
 void DateFormatTest::TestEras()
@@ -1843,7 +1882,7 @@ void DateFormatTest::TestEras()
         "MMMM dd yyyy GGGG", "fp", "-438 07 17", "July 17 0439 Before Christ", "-438 07 17",
     };
 
-    expect(EN_DATA, ARRAY_SIZE(EN_DATA), Locale("en", "", ""));
+    expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
 }
 
 void DateFormatTest::TestQuarters()
@@ -1860,9 +1899,12 @@ void DateFormatTest::TestQuarters()
         "qq",   "fp", "1970 04 01", "02",          "1970 04 01",
         "qqq",  "fp", "1970 07 01", "Q3",          "1970 07 01",
         "qqqq", "fp", "1970 10 01", "4th quarter", "1970 10 01",
+
+        "Qyy",  "fp", "2015 04 01", "215",         "2015 04 01",
+        "QQyy", "fp", "2015 07 01", "0315",        "2015 07 01",
     };
 
-    expect(EN_DATA, ARRAY_SIZE(EN_DATA), Locale("en", "", ""));
+    expect(EN_DATA, UPRV_LENGTHOF(EN_DATA), Locale("en", "", ""));
 }
 
 /**
@@ -2176,7 +2218,7 @@ void DateFormatTest::TestGenericTime() {
         "y/M/d H:mm", "pf", "2004/10/31 1:30", "2004 10 31 01:30 PST", "2004/10/31 1:30",
   };
 
-  const int32_t ZDATA_length = sizeof(ZDATA)/ sizeof(ZDATA[0]);
+  const int32_t ZDATA_length = UPRV_LENGTHOF(ZDATA);
   expect(ZDATA, ZDATA_length, en);
 
   UErrorCode status = U_ZERO_ERROR;
@@ -2193,7 +2235,7 @@ void DateFormatTest::TestGenericTime() {
     dataerrln("Fail construct SimpleDateFormat: %s", u_errorName(status));
     return;
   }
-  const int32_t formats_length = sizeof(formats)/sizeof(formats[0]);
+  const int32_t formats_length = UPRV_LENGTHOF(formats);
 
   UnicodeString test;
   SimpleDateFormat univ("yyyy MM dd HH:mm zzz", en, status);
@@ -2202,7 +2244,7 @@ void DateFormatTest::TestGenericTime() {
     "2004 01 02 03:04 PST",
     "2004 07 08 09:10 PDT"
   };
-  int32_t times_length = sizeof(times)/sizeof(times[0]);
+  int32_t times_length = UPRV_LENGTHOF(times);
   for (int i = 0; i < times_length; ++i) {
     UDate d = univ.parse(times[i], status);
     logln(UnicodeString("\ntime: ") + d);
@@ -2280,7 +2322,7 @@ void DateFormatTest::TestGenericTimeZoneOrder() {
     "y/M/d v H:mm", "pf", "2004/7/1 PT 1:00", "2004 07 01 01:00 PDT", "2004/7/1 PT 1:00",
     "v y/M/d H:mm", "pf", "PT 2004/7/1 1:00", "2004 07 01 01:00 PDT", "PT 2004/7/1 1:00",
   };
-  const int32_t XDATA_length = sizeof(XDATA)/sizeof(XDATA[0]);
+  const int32_t XDATA_length = UPRV_LENGTHOF(XDATA);
   Locale en("en");
   expect(XDATA, XDATA_length, en);
 }
@@ -2308,13 +2350,13 @@ void DateFormatTest::TestZTimeZoneParsing(void) {
     };
 
     UnicodeString result;
-    int32_t tests_length = sizeof(tests)/sizeof(tests[0]);
+    int32_t tests_length = UPRV_LENGTHOF(tests);
     for (int i = 0; i < tests_length; ++i) {
         pp.setIndex(0);
         UDate d = univ.parse(tests[i].input, pp);
         if(pp.getIndex() != tests[i].input.length()){
             errln("Test %i: setZoneString() did not succeed. Consumed: %i instead of %i",
-                  i, pp.getIndex(), tests[i].input.length()); 
+                  i, pp.getIndex(), tests[i].input.length());
             return;
         }
         result.remove();
@@ -2332,7 +2374,7 @@ void DateFormatTest::TestZTimeZoneParsing(void) {
 
 void DateFormatTest::TestHost(void)
 {
-#if U_PLATFORM_HAS_WIN32_API
+#if U_PLATFORM_USES_ONLY_WIN32_API
     Win32DateTimeTest::testLocales(this);
 #endif
 }
@@ -2348,7 +2390,7 @@ void DateFormatTest::TestRelative(int daysdelta,
 
     UErrorCode status = U_ZERO_ERROR;
 
-    FieldPosition pos(0);
+    FieldPosition pos(FieldPosition::DONT_CARE);
     UnicodeString test;
     Locale en("en");
     DateFormat *fullrelative = DateFormat::createDateInstance(DateFormat::kFullRelative, loc);
@@ -2562,6 +2604,10 @@ void DateFormatTest::TestDateFormatSymbolsClone(void)
     Locale loc("de_CH_LUCERNE");
     LocalPointer<DateFormat> fmt(
             DateFormat::createDateInstance(DateFormat::kDefault, loc));
+    if (fmt.isNull()) {
+        dataerrln("FAIL: DateFormat::createDateInstance failed for %s", loc.getName());
+        return;
+    }
     Locale valid1;
     Locale actual1;
     if (!getActualAndValidLocales(*fmt, valid1, actual1)) {
@@ -3105,8 +3151,8 @@ void DateFormatTest::TestTimeZoneDisplayName()
         { "bg", "Europe/London", "2004-07-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+01:00", "+1:00" },
         { "bg", "Europe/London", "2004-07-15T00:00:00Z", "z", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447+1", "+1:00" },
         { "bg", "Europe/London", "2004-07-15T00:00:00Z", "zzzz", "\\u0411\\u0440\\u0438\\u0442\\u0430\\u043d\\u0441\\u043a\\u043e \\u043b\\u044f\\u0442\\u043d\\u043e \\u0447\\u0430\\u0441\\u043e\\u0432\\u043e \\u0432\\u0440\\u0435\\u043c\\u0435", "+1:00" },
-        { "bg", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u0412\\u0435\\u043b\\u0438\\u043a\\u043e\\u0431\\u0440\\u0438\\u0442\\u0430\\u043d\\u0438\\u044f", "Europe/London" },
-        { "bg", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u0412\\u0435\\u043b\\u0438\\u043a\\u043e\\u0431\\u0440\\u0438\\u0442\\u0430\\u043d\\u0438\\u044f", "Europe/London" },
+        { "bg", "Europe/London", "2004-07-15T00:00:00Z", "v", "\\u041E\\u0431\\u0435\\u0434\\u0438\\u043D\\u0435\\u043D\\u043E\\u0442\\u043E \\u043A\\u0440\\u0430\\u043B\\u0441\\u0442\\u0432\\u043E", "Europe/London" },
+        { "bg", "Europe/London", "2004-07-15T00:00:00Z", "vvvv", "\\u041E\\u0431\\u0435\\u0434\\u0438\\u043D\\u0435\\u043D\\u043E\\u0442\\u043E \\u043A\\u0440\\u0430\\u043B\\u0441\\u0442\\u0432\\u043E", "Europe/London" },
 
         { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "Z", "-0300", "-3:00" },
         { "bg", "Etc/GMT+3", "2004-01-15T00:00:00Z", "ZZZZ", "\\u0413\\u0440\\u0438\\u043D\\u0443\\u0438\\u0447-03:00", "-3:00" },
@@ -3386,7 +3432,7 @@ void DateFormatTest::TestTimeZoneDisplayName()
         ASSERT_OK(status);
         cal->adoptTimeZone(tz);
         UnicodeString result;
-        FieldPosition pos(0);
+        FieldPosition pos(FieldPosition::DONT_CARE);
         fmt.format(*cal,result,pos);
         if (result != info[4]) {
             errln(info[0] + ";" + info[1] + ";" + info[2] + ";" + info[3] + " expected: '" +
@@ -3711,7 +3757,7 @@ void DateFormatTest::TestGMTParsing() {
         "HH:mm:ssZZZZZ",    "14:25:45Z",            "14:25:45 +0000",
         "HH:mm:ssZZZZZ",    "15:00:00-08:00",       "15:00:00 -0800",
     };
-    const int32_t DATA_len = sizeof(DATA)/sizeof(DATA[0]);
+    const int32_t DATA_len = UPRV_LENGTHOF(DATA);
     expectParse(DATA, DATA_len, Locale("en"));
 }
 
@@ -3725,7 +3771,7 @@ void DateFormatTest::Test6880() {
     TimeZone *tz = TimeZone::createTimeZone("Asia/Shanghai");
     GregorianCalendar gcal(*tz, status);
     if (failure(status, "construct GregorianCalendar", TRUE)) return;
-    
+
     gcal.clear();
     gcal.set(1900, UCAL_JULY, 1, 12, 00);   // offset 8:05:43
     d1 = gcal.getTime(status);
@@ -3840,75 +3886,75 @@ void DateFormatTest::TestNumberAsStringParsing()
     }
 }
 
-void DateFormatTest::TestISOEra() { 
-   
-    const char* data[] = { 
-    // input, output 
-    "BC 4004-10-23T07:00:00Z", "BC 4004-10-23T07:00:00Z", 
-    "AD 4004-10-23T07:00:00Z", "AD 4004-10-23T07:00:00Z", 
-    "-4004-10-23T07:00:00Z"  , "BC 4005-10-23T07:00:00Z", 
-    "4004-10-23T07:00:00Z"   , "AD 4004-10-23T07:00:00Z", 
-    }; 
-    int32_t numData = 8; 
-    UErrorCode status = U_ZERO_ERROR; 
-    // create formatter 
-    SimpleDateFormat *fmt1 = new SimpleDateFormat(UnicodeString("GGG yyyy-MM-dd'T'HH:mm:ss'Z"), status); 
-    failure(status, "new SimpleDateFormat", TRUE); 
+void DateFormatTest::TestISOEra() {
+
+    const char* data[] = {
+    // input, output
+    "BC 4004-10-23T07:00:00Z", "BC 4004-10-23T07:00:00Z",
+    "AD 4004-10-23T07:00:00Z", "AD 4004-10-23T07:00:00Z",
+    "-4004-10-23T07:00:00Z"  , "BC 4005-10-23T07:00:00Z",
+    "4004-10-23T07:00:00Z"   , "AD 4004-10-23T07:00:00Z",
+    };
+
+    int32_t numData = 8;
+
+    UErrorCode status = U_ZERO_ERROR;
+
+    // create formatter
+    SimpleDateFormat *fmt1 = new SimpleDateFormat(UnicodeString("GGG yyyy-MM-dd'T'HH:mm:ss'Z"), status);
+    failure(status, "new SimpleDateFormat", TRUE);
     if (status == U_MISSING_RESOURCE_ERROR) {
         if (fmt1 != NULL) {
             delete fmt1;
         }
         return;
     }
-    for(int i=0; i < numData; i+=2) { 
-        // create input string 
-        UnicodeString in = data[i]; 
-        // parse string to date 
-        UDate dt1 = fmt1->parse(in, status); 
-        failure(status, "fmt->parse", TRUE); 
-        // format date back to string 
-        UnicodeString out; 
-        out = fmt1->format(dt1, out); 
-        logln(out); 
-        // check that roundtrip worked as expected 
-        UnicodeString expected = data[i+1]; 
-        if (out != expected) { 
-            dataerrln((UnicodeString)"FAIL: " + in + " -> " + out + " expected -> " + expected); 
-        } 
-    } 
-    delete fmt1; 
-} 
-void DateFormatTest::TestFormalChineseDate() { 
-   
-    UErrorCode status = U_ZERO_ERROR; 
+    for(int i=0; i < numData; i+=2) {
+        // create input string
+        UnicodeString in = data[i];
+
+        // parse string to date
+        UDate dt1 = fmt1->parse(in, status);
+        failure(status, "fmt->parse", TRUE);
+
+        // format date back to string
+        UnicodeString out;
+        out = fmt1->format(dt1, out);
+        logln(out);
+
+        // check that roundtrip worked as expected
+        UnicodeString expected = data[i+1];
+        if (out != expected) {
+            dataerrln((UnicodeString)"FAIL: " + in + " -> " + out + " expected -> " + expected);
+        }
+    }
+
+    delete fmt1;
+}
+void DateFormatTest::TestFormalChineseDate() {
+
+    UErrorCode status = U_ZERO_ERROR;
     UnicodeString pattern ("y\\u5e74M\\u6708d\\u65e5", -1, US_INV );
     pattern = pattern.unescape();
     UnicodeString override ("y=hanidec;M=hans;d=hans", -1, US_INV );
-    
-    // create formatter 
+
+    // create formatter
     SimpleDateFormat *sdf = new SimpleDateFormat(pattern,override,Locale::getChina(),status);
     if (failure(status, "new SimpleDateFormat with override", TRUE)) {
         return;
     }
 
     UDate thedate = date(2009-1900, UCAL_JULY, 28);
-    FieldPosition pos(0);
+    FieldPosition pos(FieldPosition::DONT_CARE);
     UnicodeString result;
     sdf->format(thedate,result,pos);
-    UnicodeString expected = "\\u4e8c\\u3007\\u3007\\u4e5d\\u5e74\\u4e03\\u6708\\u4e8c\\u5341\\u516b\\u65e5"; 
+
+    UnicodeString expected = "\\u4e8c\\u3007\\u3007\\u4e5d\\u5e74\\u4e03\\u6708\\u4e8c\\u5341\\u516b\\u65e5";
     expected = expected.unescape();
-    if (result != expected) { 
-        dataerrln((UnicodeString)"FAIL: -> " + result + " expected -> " + expected); 
-    } 
+    if (result != expected) {
+        dataerrln((UnicodeString)"FAIL: -> " + result + " expected -> " + expected);
+    }
+
     UDate parsedate = sdf->parse(expected,status);
     if ( parsedate != thedate ) {
         UnicodeString pat1 ("yyyy-MM-dd'T'HH:mm:ss'Z'", -1, US_INV );
@@ -3916,7 +3962,7 @@ void DateFormatTest::TestFormalChineseDate() {
         UnicodeString parsedres,expres;
         usf->format(parsedate,parsedres,pos);
         usf->format(thedate,expres,pos);
-        dataerrln((UnicodeString)"FAIL: parsed -> " + parsedres + " expected -> " + expres); 
+        dataerrln((UnicodeString)"FAIL: parsed -> " + parsedres + " expected -> " + expres);
         delete usf;
     }
     delete sdf;
@@ -3927,7 +3973,7 @@ void DateFormatTest::TestFormalChineseDate() {
 void DateFormatTest::TestStandAloneGMTParse() {
     UErrorCode status = U_ZERO_ERROR;
     SimpleDateFormat *sdf = new SimpleDateFormat("ZZZZ", Locale(""), status);
-    
+
     if (U_SUCCESS(status)) {
 
         UnicodeString inText("GMT$$$");
@@ -4028,7 +4074,7 @@ void DateFormatTest::TestMonthPatterns()
         { "root@calendar=chinese",    -3,                 { UnicodeString("ren-chen-4-2"),  UnicodeString("ren-chen-4bis-2"),       UnicodeString("ren-chen-5-2") } },
         { "root@calendar=chinese",    -4,                 { UnicodeString("ren-chen M04 2"),  UnicodeString("ren-chen M04bis 2"),   UnicodeString("ren-chen M05 2") } },
         { "en@calendar=gregorian",    -3,                 { UnicodeString("2012-4-22"),     UnicodeString("2012-5-22"),             UnicodeString("2012-6-20") } },
-        { "en@calendar=chinese",      DateFormat::kLong,  { UnicodeString("Month4 2, 2012(ren-chen)"), UnicodeString("Month4bis 2, 2012(ren-chen)"), UnicodeString("Month5 2, 2012(ren-chen)") } },
+        { "en@calendar=chinese",      DateFormat::kLong,  { UnicodeString("Fourth Month 2, 2012(ren-chen)"), UnicodeString("Fourth Monthbis 2, 2012(ren-chen)"), UnicodeString("Fifth Month 2, 2012(ren-chen)") } },
         { "en@calendar=chinese",      DateFormat::kShort, { UnicodeString("4/2/2012"),      UnicodeString("4bis/2/2012"),           UnicodeString("5/2/2012") } },
         { "zh@calendar=chinese",      DateFormat::kLong,  { CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u56DB\\u6708\\u521D\\u4E8C"),
                                                             CharsToUnicodeString("2012\\u58EC\\u8FB0\\u5E74\\u95F0\\u56DB\\u6708\\u521D\\u4E8C"),
@@ -4052,7 +4098,7 @@ void DateFormatTest::TestMonthPatterns()
                                                             CharsToUnicodeString("2 s\\u00ECyu\\u00E8bis ren-chen"),
                                                             CharsToUnicodeString("2 w\\u01D4yu\\u00E8 ren-chen") } },
         { "fr@calendar=chinese",      DateFormat::kShort, { UnicodeString("2/4/29"),        UnicodeString("2/4bis/29"),             UnicodeString("2/5/29") } },
-        { "en@calendar=dangi",        DateFormat::kLong,  { UnicodeString("Month3bis 2, 2012(29)"),  UnicodeString("Month4 2, 2012(29)"),       UnicodeString("Month5 1, 2012(29)") } },
+        { "en@calendar=dangi",        DateFormat::kLong,  { UnicodeString("Third Monthbis 2, 2012(ren-chen)"),  UnicodeString("Fourth Month 2, 2012(ren-chen)"),       UnicodeString("Fifth Month 1, 2012(ren-chen)") } },
         { "en@calendar=dangi",        DateFormat::kShort, { UnicodeString("3bis/2/2012"),   UnicodeString("4/2/2012"),              UnicodeString("5/1/2012") } },
         { "en@calendar=dangi",        -2,                 { UnicodeString("78x29-3bis-2"),  UnicodeString("78x29-4-2"),             UnicodeString("78x29-5-1") } },
         { "ko@calendar=dangi",        DateFormat::kLong,  { CharsToUnicodeString("\\uC784\\uC9C4\\uB144 \\uC7243\\uC6D4 2\\uC77C"),
@@ -4064,7 +4110,7 @@ void DateFormatTest::TestMonthPatterns()
         // terminator
         { NULL,                       0,                  { UnicodeString(""), UnicodeString(""), UnicodeString("") } }
     };
-    
+
     //.                               style: -1        -2            -3       -4
     const UnicodeString customPatterns[] = { "y-Ml-d", "G'x'y-Ml-d", "U-M-d", "U MMM d" }; // like old root pattern, using 'l'
 
@@ -4088,7 +4134,7 @@ void DateFormatTest::TestMonthPatterns()
                         rootChineseCalendar->set(datePtr->year, datePtr->month-1, datePtr->day);
                         rootChineseCalendar->set(UCAL_IS_LEAP_MONTH, datePtr->isLeapMonth);
                         UnicodeString result;
-                        FieldPosition fpos(0);
+                        FieldPosition fpos(FieldPosition::DONT_CARE);
                         dmft->format(*rootChineseCalendar, result, fpos);
                         if ( result.compare(itemPtr->dateString[idate]) != 0 ) {
                             errln( UnicodeString("FAIL: Chinese calendar format for locale ") + UnicodeString(itemPtr->locale) + ", style " + itemPtr->style +
@@ -4173,7 +4219,7 @@ void DateFormatTest::TestContext()
            } else {
                sdmft->setContext(itemPtr->capitalizationContext, status);
                UnicodeString result;
-               FieldPosition pos(0);
+               FieldPosition pos(FieldPosition::DONT_CARE);
                sdmft->format(*cal, result, pos);
                if (result.compare(itemPtr->expectedFormat) != 0) {
                    errln(UnicodeString("FAIL: format for locale ") + UnicodeString(itemPtr->locale) +
@@ -4287,7 +4333,7 @@ void DateFormatTest::TestNonGregoFmtParse()
                     cal->set(UCAL_HOUR_OF_DAY, caftItemPtr->hour);
                     cal->set(UCAL_MINUTE, caftItemPtr->minute);
                     UnicodeString result;
-                    FieldPosition fpos(0);
+                    FieldPosition fpos(FieldPosition::DONT_CARE);
                     dfmt->format(*cal, result, fpos);
                     if ( result.compare(caftItemPtr->formattedDate) != 0 ) {
                         errln( UnicodeString("FAIL: date format for locale ") + UnicodeString(itemPtr->locale) + ", style " + itemPtr->style +
@@ -4317,6 +4363,67 @@ void DateFormatTest::TestNonGregoFmtParse()
     }
 }
 
+typedef struct {
+    const char*         localeID;
+    DateFormat::EStyle  style;
+    UnicodeString       expectPattern;
+    UnicodeString       expectFormat;
+} TestFmtWithNumSysItem;
+enum { kBBufMax = 128 };
+void DateFormatTest::TestFormatsWithNumberSystems()
+{
+    LocalPointer<TimeZone> zone(TimeZone::createTimeZone(UnicodeString("UTC")));
+    const UDate date = 1451556000000.0; // for UTC: grego 31-Dec-2015 10 AM, hebrew 19 tevet 5776, chinese yi-wei 11mo 21day
+    const TestFmtWithNumSysItem items[] = {
+        { "haw@calendar=gregorian", DateFormat::kShort, UnicodeString("d/M/yy"),               UnicodeString("31/xii/15") },
+        { "he@calendar=hebrew",     DateFormat::kLong, CharsToUnicodeString("d \\u05D1MMMM y"), CharsToUnicodeString("\\u05D9\\u05F4\\u05D8 \\u05D1\\u05D8\\u05D1\\u05EA \\u05EA\\u05E9\\u05E2\\u05F4\\u05D5") }, // "י״ט בטבת תשע״ו"
+        { "zh@calendar=chinese",      DateFormat::kLong, CharsToUnicodeString("rU\\u5E74MMMd"), CharsToUnicodeString("2015\\u4E59\\u672A\\u5E74\\u51AC\\u6708\\u5EFF\\u4E00") }, // "2015乙未年冬月廿一"
+        { "zh_Hant@calendar=chinese", DateFormat::kLong, CharsToUnicodeString("rU\\u5E74MMMd"), CharsToUnicodeString("2015\\u4E59\\u672A\\u5E74\\u51AC\\u6708\\u5EFF\\u4E00") }, // "2015乙未年冬月廿一"
+        { "ja@calendar=chinese", DateFormat::kLong, CharsToUnicodeString("U\\u5E74MMMd\\u65E5"), CharsToUnicodeString("\\u4E59\\u672A\\u5E74\\u5341\\u4E00\\u6708\\u4E8C\\u5341\\u4E00\\u65E5") }, // "乙未年十一月二十一日"
+        { NULL, DateFormat::kNone, UnicodeString(""), UnicodeString("") },
+    };
+    const TestFmtWithNumSysItem * itemPtr;
+    for (itemPtr = items; itemPtr->localeID != NULL; itemPtr++) {
+        char bExpected[kBBufMax];
+        char bResult[kBBufMax];
+        UErrorCode status = U_ZERO_ERROR;
+        Locale locale = Locale::createFromName(itemPtr->localeID);
+        LocalPointer<Calendar> cal(Calendar::createInstance(zone.orphan(), locale, status));
+        if (U_FAILURE(status)) {
+            dataerrln("Calendar::createInstance fails for locale %s, status %s", itemPtr->localeID, u_errorName(status));
+            continue;
+        }
+        cal->setTime(date, status);
+        if (U_FAILURE(status)) {
+            dataerrln("Calendar::setTime fails for locale %s, date %.1f, status %s", itemPtr->localeID, date, u_errorName(status));
+            continue;
+        }
+        LocalPointer<SimpleDateFormat> sdfmt(static_cast<SimpleDateFormat *>(DateFormat::createDateInstance(itemPtr->style, locale)));
+        if (sdfmt.isNull()) {
+            dataerrln("DateFormat::createDateInstance fails for locale %s", itemPtr->localeID);
+            continue;
+        }
+        UnicodeString getFormat;
+        sdfmt->format(*(cal.getAlias()), getFormat, NULL, status);
+        if (U_FAILURE(status)) {
+            errln("DateFormat::format fails for locale %s, status %s", itemPtr->localeID, u_errorName(status));
+            continue;
+        }
+        if (getFormat.compare(itemPtr->expectFormat) != 0) {
+            itemPtr->expectFormat.extract(0, itemPtr->expectFormat.length(), bExpected, kBBufMax);
+            getFormat.extract(0, getFormat.length(), bResult, kBBufMax);
+            errln("DateFormat::format for locale %s, expected \"%s\", got \"%s\"", itemPtr->localeID, bExpected, bResult);
+        }
+        UnicodeString getPattern;
+        sdfmt->toPattern(getPattern);
+        if (getPattern.compare(itemPtr->expectPattern) != 0) {
+            itemPtr->expectPattern.extract(0, itemPtr->expectPattern.length(), bExpected, kBBufMax);
+            getPattern.extract(0, getPattern.length(), bResult, kBBufMax);
+            errln("DateFormat::toPattern() for locale %s, expected \"%s\", got \"%s\"", itemPtr->localeID, bExpected, bResult);
+        }
+    }
+}
+
 static const UDate TEST_DATE = 1326585600000.;  // 2012-jan-15
 
 void DateFormatTest::TestDotAndAtLeniency() {
@@ -4394,7 +4501,7 @@ typedef struct {
 
 void DateFormatTest::TestDateFormatLeniency() {
     // For details see http://bugs.icu-project.org/trac/ticket/10261
-    
+
     const UDate july022008 = 1215000001979.0;
     const TestDateFormatLeniencyItem items[] = {
         //locale    leniency    parse String                    pattern                             expected result
@@ -4405,7 +4512,7 @@ void DateFormatTest::TestDateFormatLeniency() {
         { "en",     true,       UnicodeString("2008-Jan--02"),  UnicodeString("yyyy-MMM' -- 'dd"),  UnicodeString("2008-Jan -- 02") },
         { "en",     false,      UnicodeString("2008-Jan--02"),  UnicodeString("yyyy-MMM' -- 'dd"),  UnicodeString("") },
         // terminator
-        { NULL,     true,       UnicodeString(""),              UnicodeString(""),                  UnicodeString("") }                
+        { NULL,     true,       UnicodeString(""),              UnicodeString(""),                  UnicodeString("") }
     };
     UErrorCode status = U_ZERO_ERROR;
     LocalPointer<Calendar> cal(Calendar::createInstance(status));
@@ -4417,7 +4524,7 @@ void DateFormatTest::TestDateFormatLeniency() {
     const TestDateFormatLeniencyItem * itemPtr;
     LocalPointer<SimpleDateFormat> sdmft;
     for (itemPtr = items; itemPtr->locale != NULL; itemPtr++ ) {
-                                        
+
        Locale locale = Locale::createFromName(itemPtr->locale);
        status = U_ZERO_ERROR;
        ParsePosition pos(0);
@@ -4428,37 +4535,37 @@ void DateFormatTest::TestDateFormatLeniency() {
        }
        sdmft->setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, itemPtr->leniency, status).
               setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, itemPtr->leniency, status).
-              setBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, itemPtr->leniency, status);
-       UDate d = sdmft->parse(itemPtr->parseString, pos);       
+              setBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, itemPtr->leniency, status);
+       UDate d = sdmft->parse(itemPtr->parseString, pos);
 
        if(itemPtr->expectedResult.length() == 0) {
            if(pos.getErrorIndex() != -1) {
                continue;
            } else {
-                errln("error: unexpected parse success - " + itemPtr->parseString + 
-                    " - pattern " + itemPtr->pattern + 
-                    " - error index " + pos.getErrorIndex() + 
+                errln("error: unexpected parse success - " + itemPtr->parseString +
+                    " - pattern " + itemPtr->pattern +
+                    " - error index " + pos.getErrorIndex() +
                     " - leniency " + itemPtr->leniency);
                 continue;
            }
        }
-       if(pos.getErrorIndex() != -1) { 
-           errln("error: parse error for string - "  + itemPtr->parseString + 
-                 " - pattern " + itemPtr->pattern + 
-                 " - idx " + pos.getIndex() + 
-                 " - error index "+pos.getErrorIndex() + 
-                 " - leniency " + itemPtr->leniency); 
-            continue; 
+       if(pos.getErrorIndex() != -1) {
+           errln("error: parse error for string - "  + itemPtr->parseString +
+                 " - pattern " + itemPtr->pattern +
+                 " - idx " + pos.getIndex() +
+                 " - error index "+pos.getErrorIndex() +
+                 " - leniency " + itemPtr->leniency);
+            continue;
         }
 
-       UnicodeString formatResult(""); 
+       UnicodeString formatResult("");
        sdmft->format(d, formatResult);
-       if(formatResult.compare(itemPtr->expectedResult) != 0) { 
-           errln("error: unexpected format result. pattern["+itemPtr->pattern+"] expected[" + itemPtr->expectedResult + "]  but result was[" + formatResult + "]"); 
+       if(formatResult.compare(itemPtr->expectedResult) != 0) {
+           errln("error: unexpected format result. pattern["+itemPtr->pattern+"] expected[" + itemPtr->expectedResult + "]  but result was[" + formatResult + "]");
            continue;
-        } else { 
-            logln("formatted results match! - " + formatResult);  
-        } 
+        } else {
+            logln("formatted results match! - " + formatResult);
+        }
 
     }
 }
@@ -4472,36 +4579,36 @@ typedef struct {
 } TestMultiPatternMatchItem;
 
 void DateFormatTest::TestParseMultiPatternMatch() {
-        // For details see http://bugs.icu-project.org/trac/ticket/10336 
+        // For details see http://bugs.icu-project.org/trac/ticket/10336
     const TestMultiPatternMatchItem items[] = {
-          // leniency    parse String                                 pattern                               expected result 
-            {true,       UnicodeString("2013-Sep 13"),                UnicodeString("yyyy-MMM dd"),         UnicodeString("2013-Sep 13")}, 
-            {true,       UnicodeString("2013-September 14"),          UnicodeString("yyyy-MMM dd"),         UnicodeString("2013-Sep 14")}, 
-            {false,      UnicodeString("2013-September 15"),          UnicodeString("yyyy-MMM dd"),         UnicodeString("")}, 
-            {false,      UnicodeString("2013-September 16"),          UnicodeString("yyyy-MMMM dd"),        UnicodeString("2013-September 16")}, 
-            {true,       UnicodeString("2013-Sep 17"),                UnicodeString("yyyy-LLL dd"),         UnicodeString("2013-Sep 17")}, 
-            {true,       UnicodeString("2013-September 18"),          UnicodeString("yyyy-LLL dd"),         UnicodeString("2013-Sep 18")}, 
-            {false,      UnicodeString("2013-September 19"),          UnicodeString("yyyy-LLL dd"),         UnicodeString("")}, 
-            {false,      UnicodeString("2013-September 20"),          UnicodeString("yyyy-LLLL dd"),        UnicodeString("2013-September 20")}, 
-            {true,       UnicodeString("2013 Sat Sep 21"),            UnicodeString("yyyy EEE MMM dd"),     UnicodeString("2013 Sat Sep 21")}, 
-            {true,       UnicodeString("2013 Sunday Sep 22"),         UnicodeString("yyyy EEE MMM dd"),     UnicodeString("2013 Sun Sep 22")}, 
-            {false,      UnicodeString("2013 Monday Sep 23"),         UnicodeString("yyyy EEE MMM dd"),     UnicodeString("")}, 
-            {false,      UnicodeString("2013 Tuesday Sep 24"),        UnicodeString("yyyy EEEE MMM dd"),    UnicodeString("2013 Tuesday Sep 24")}, 
-            {true,       UnicodeString("2013 Wed Sep 25"),            UnicodeString("yyyy eee MMM dd"),     UnicodeString("2013 Wed Sep 25")}, 
-            {true,       UnicodeString("2013 Thu Sep 26"),            UnicodeString("yyyy eee MMM dd"),     UnicodeString("2013 Thu Sep 26")}, 
-            {false,      UnicodeString("2013 Friday Sep 27"),         UnicodeString("yyyy eee MMM dd"),     UnicodeString("")}, 
-            {false,      UnicodeString("2013 Saturday Sep 28"),       UnicodeString("yyyy eeee MMM dd"),    UnicodeString("2013 Saturday Sep 28")}, 
-            {true,       UnicodeString("2013 Sun Sep 29"),            UnicodeString("yyyy ccc MMM dd"),     UnicodeString("2013 Sun Sep 29")}, 
-            {true,       UnicodeString("2013 Monday Sep 30"),         UnicodeString("yyyy ccc MMM dd"),     UnicodeString("2013 Mon Sep 30")}, 
-            {false,      UnicodeString("2013 Sunday Oct 13"),         UnicodeString("yyyy ccc MMM dd"),     UnicodeString("")}, 
-            {false,      UnicodeString("2013 Monday Oct 14"),         UnicodeString("yyyy cccc MMM dd"),    UnicodeString("2013 Monday Oct 14")}, 
-            {true,       UnicodeString("2013 Oct 15 Q4"),             UnicodeString("yyyy MMM dd QQQ"),     UnicodeString("2013 Oct 15 Q4")}, 
-            {true,       UnicodeString("2013 Oct 16 4th quarter"),    UnicodeString("yyyy MMM dd QQQ"),     UnicodeString("2013 Oct 16 Q4")}, 
-            {false,      UnicodeString("2013 Oct 17 4th quarter"),    UnicodeString("yyyy MMM dd QQQ"),     UnicodeString("")}, 
-            {false,      UnicodeString("2013 Oct 18 Q4"),             UnicodeString("yyyy MMM dd QQQ"),     UnicodeString("2013 Oct 18 Q4")}, 
-            {true,       UnicodeString("2013 Oct 19 Q4"),             UnicodeString("yyyy MMM dd qqqq"),    UnicodeString("2013 Oct 19 4th quarter")}, 
-            {true,       UnicodeString("2013 Oct 20 4th quarter"),    UnicodeString("yyyy MMM dd qqqq"),    UnicodeString("2013 Oct 20 4th quarter")}, 
-            {false,      UnicodeString("2013 Oct 21 Q4"),             UnicodeString("yyyy MMM dd qqqq"),    UnicodeString("")}, 
+          // leniency    parse String                                 pattern                               expected result
+            {true,       UnicodeString("2013-Sep 13"),                UnicodeString("yyyy-MMM dd"),         UnicodeString("2013-Sep 13")},
+            {true,       UnicodeString("2013-September 14"),          UnicodeString("yyyy-MMM dd"),         UnicodeString("2013-Sep 14")},
+            {false,      UnicodeString("2013-September 15"),          UnicodeString("yyyy-MMM dd"),         UnicodeString("")},
+            {false,      UnicodeString("2013-September 16"),          UnicodeString("yyyy-MMMM dd"),        UnicodeString("2013-September 16")},
+            {true,       UnicodeString("2013-Sep 17"),                UnicodeString("yyyy-LLL dd"),         UnicodeString("2013-Sep 17")},
+            {true,       UnicodeString("2013-September 18"),          UnicodeString("yyyy-LLL dd"),         UnicodeString("2013-Sep 18")},
+            {false,      UnicodeString("2013-September 19"),          UnicodeString("yyyy-LLL dd"),         UnicodeString("")},
+            {false,      UnicodeString("2013-September 20"),          UnicodeString("yyyy-LLLL dd"),        UnicodeString("2013-September 20")},
+            {true,       UnicodeString("2013 Sat Sep 21"),            UnicodeString("yyyy EEE MMM dd"),     UnicodeString("2013 Sat Sep 21")},
+            {true,       UnicodeString("2013 Sunday Sep 22"),         UnicodeString("yyyy EEE MMM dd"),     UnicodeString("2013 Sun Sep 22")},
+            {false,      UnicodeString("2013 Monday Sep 23"),         UnicodeString("yyyy EEE MMM dd"),     UnicodeString("")},
+            {false,      UnicodeString("2013 Tuesday Sep 24"),        UnicodeString("yyyy EEEE MMM dd"),    UnicodeString("2013 Tuesday Sep 24")},
+            {true,       UnicodeString("2013 Wed Sep 25"),            UnicodeString("yyyy eee MMM dd"),     UnicodeString("2013 Wed Sep 25")},
+            {true,       UnicodeString("2013 Thu Sep 26"),            UnicodeString("yyyy eee MMM dd"),     UnicodeString("2013 Thu Sep 26")},
+            {false,      UnicodeString("2013 Friday Sep 27"),         UnicodeString("yyyy eee MMM dd"),     UnicodeString("")},
+            {false,      UnicodeString("2013 Saturday Sep 28"),       UnicodeString("yyyy eeee MMM dd"),    UnicodeString("2013 Saturday Sep 28")},
+            {true,       UnicodeString("2013 Sun Sep 29"),            UnicodeString("yyyy ccc MMM dd"),     UnicodeString("2013 Sun Sep 29")},
+            {true,       UnicodeString("2013 Monday Sep 30"),         UnicodeString("yyyy ccc MMM dd"),     UnicodeString("2013 Mon Sep 30")},
+            {false,      UnicodeString("2013 Sunday Oct 13"),         UnicodeString("yyyy ccc MMM dd"),     UnicodeString("")},
+            {false,      UnicodeString("2013 Monday Oct 14"),         UnicodeString("yyyy cccc MMM dd"),    UnicodeString("2013 Monday Oct 14")},
+            {true,       UnicodeString("2013 Oct 15 Q4"),             UnicodeString("yyyy MMM dd QQQ"),     UnicodeString("2013 Oct 15 Q4")},
+            {true,       UnicodeString("2013 Oct 16 4th quarter"),    UnicodeString("yyyy MMM dd QQQ"),     UnicodeString("2013 Oct 16 Q4")},
+            {false,      UnicodeString("2013 Oct 17 4th quarter"),    UnicodeString("yyyy MMM dd QQQ"),     UnicodeString("")},
+            {false,      UnicodeString("2013 Oct 18 Q4"),             UnicodeString("yyyy MMM dd QQQ"),     UnicodeString("2013 Oct 18 Q4")},
+            {true,       UnicodeString("2013 Oct 19 Q4"),             UnicodeString("yyyy MMM dd qqqq"),    UnicodeString("2013 Oct 19 4th quarter")},
+            {true,       UnicodeString("2013 Oct 20 4th quarter"),    UnicodeString("yyyy MMM dd qqqq"),    UnicodeString("2013 Oct 20 4th quarter")},
+            {false,      UnicodeString("2013 Oct 21 Q4"),             UnicodeString("yyyy MMM dd qqqq"),    UnicodeString("")},
             {false,      UnicodeString("2013 Oct 22 4th quarter"),    UnicodeString("yyyy MMM dd qqqq"),    UnicodeString("2013 Oct 22 4th quarter")},
             {false,      UnicodeString("--end--"),                    UnicodeString(""),                    UnicodeString("")},
     };
@@ -4527,30 +4634,30 @@ void DateFormatTest::TestParseMultiPatternMatch() {
            continue;
        }
        sdmft->setBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, itemPtr->leniency, status);
-       UDate d = sdmft->parse(itemPtr->parseString, pos); 
-       
+       UDate d = sdmft->parse(itemPtr->parseString, pos);
+
        if(itemPtr->expectedResult.length() == 0) {
            if(pos.getErrorIndex() != -1) {
                continue;
            } else {
-                errln("error: unexpected parse success - " + itemPtr->parseString + 
-                    " - error index " + pos.getErrorIndex() + 
+                errln("error: unexpected parse success - " + itemPtr->parseString +
+                    " - error index " + pos.getErrorIndex() +
                     " - leniency " + itemPtr->leniency);
                 continue;
            }
         }
-        if(pos.getErrorIndex() != -1) { 
-            errln("error: parse error for string - " +itemPtr->parseString + " -- idx["+pos.getIndex()+"] errIdx["+pos.getErrorIndex()+"]"); 
-            continue; 
+        if(pos.getErrorIndex() != -1) {
+            errln("error: parse error for string - " +itemPtr->parseString + " -- idx["+pos.getIndex()+"] errIdx["+pos.getErrorIndex()+"]");
+            continue;
         }
 
-        UnicodeString formatResult(""); 
+        UnicodeString formatResult("");
         sdmft->format(d, formatResult);
-        if(formatResult.compare(itemPtr->expectedResult) != 0) { 
-            errln("error: unexpected format result. expected[" + itemPtr->expectedResult + "]  but result was[" + formatResult + "]"); 
-        } else { 
-            logln("formatted results match! - " + formatResult);  
-        } 
+        if(formatResult.compare(itemPtr->expectedResult) != 0) {
+            errln("error: unexpected format result. expected[" + itemPtr->expectedResult + "]  but result was[" + formatResult + "]");
+        } else {
+            logln("formatted results match! - " + formatResult);
+        }
     }
     delete sdmft;
 }
@@ -4568,7 +4675,7 @@ void DateFormatTest::TestParseLeniencyAPIs() {
     assertTrue("isCalendarLenient default", fmt->isCalendarLenient());
     assertTrue("ALLOW_WHITESPACE default", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status));
     assertTrue("ALLOW_NUMERIC default", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status));
-    assertTrue("PARTIAL_MATCH default", fmt->getBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, status));
+    assertTrue("PARTIAL_MATCH default", fmt->getBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, status));
     assertTrue("MULTIPLE_PATTERNS default", fmt->getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status));
 
     // Set calendar to strict
@@ -4587,7 +4694,7 @@ void DateFormatTest::TestParseLeniencyAPIs() {
     assertFalse("ALLOW_WHITESPACE after setLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status));
     assertFalse("ALLOW_NUMERIC  after setLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status));
     // These two boolean attributes are NOT affected according to the API specification
-    assertTrue("PARTIAL_MATCH after setLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, status));
+    assertTrue("PARTIAL_MATCH after setLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, status));
     assertTrue("MULTIPLE_PATTERNS after setLenient(FALSE)", fmt->getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status));
 
     // Allow white space leniency
@@ -4624,7 +4731,7 @@ void DateFormatTest::TestNumberFormatOverride() {
         fmt->adoptNumberFormat(fields, check_nf, status);
         assertSuccess("adoptNumberFormat check_nf", status);
 
-        const NumberFormat* get_nf = fmt->getNumberFormatForField('M');
+        const NumberFormat* get_nf = fmt->getNumberFormatForField((UChar)0x004D /*'M'*/);
         if (get_nf != check_nf) errln("FAIL: getter and setter do not work");
     }
     NumberFormat* check_nf = NumberFormat::createInstance(Locale("en_US"), status);
@@ -4639,12 +4746,12 @@ void DateFormatTest::TestNumberFormatOverride() {
         { "MdMMd", "\\u521D\\u516D \\u5341\\u4E94"},
         { "mixed", "\\u521D\\u516D \\u5341\\u4E94"}
     };
-    
+
     UDate test_date = date(97, 6 - 1, 15);
 
-    for(int i=0; i < (int)(sizeof(DATA)/sizeof(DATA[0])); i++){
+    for(int i=0; i < UPRV_LENGTHOF(DATA); i++){
         fields = DATA[i][0];
-        
+
         LocalPointer<SimpleDateFormat> fmt;
         fmt.adoptInsteadAndCheckErrorCode(new SimpleDateFormat((UnicodeString)"MM d", status), status);
         assertSuccess("SimpleDateFormat with pattern MM d", status);
@@ -4660,7 +4767,7 @@ void DateFormatTest::TestNumberFormatOverride() {
             fields = (UnicodeString) "M";
             fmt->adoptNumberFormat(fields, singleOverrideNF, status);
             assertSuccess("adoptNumberFormat singleOverrideNF", status);
-            
+
             fmt->adoptNumberFormat(overrideNF);
         } else if (fields == (UnicodeString) "Mo"){ // o is invlid field
             fmt->adoptNumberFormat(fields, overrideNF, status);
@@ -4674,12 +4781,12 @@ void DateFormatTest::TestNumberFormatOverride() {
         }
 
         UnicodeString result;
-        FieldPosition pos(0);
+        FieldPosition pos(FieldPosition::DONT_CARE);
         fmt->format(test_date,result, pos);
 
         UnicodeString expected = ((UnicodeString)DATA[i][1]).unescape();;
 
-        if (result != expected) 
+        if (result != expected)
             errln("FAIL: Expected " + expected + " get: " + result);
     }
 }
@@ -4692,7 +4799,7 @@ void DateFormatTest::TestCreateInstanceForSkeleton() {
         return;
     }
     UnicodeString result;
-    FieldPosition pos(0);
+    FieldPosition pos(FieldPosition::DONT_CARE);
     fmt->format(date(98, 5-1, 25), result, pos);
     assertEquals("format yMMMMd", "May 25, 1998", result);
     fmt.adoptInstead(DateFormat::createInstanceForSkeleton(
@@ -4716,7 +4823,7 @@ void DateFormatTest::TestCreateInstanceForSkeletonDefault() {
         return;
     }
     UnicodeString result;
-    FieldPosition pos(0);
+    FieldPosition pos(FieldPosition::DONT_CARE);
     fmt->format(date(98, 5-1, 25), result, pos);
     assertEquals("format yMMMd", "May 25, 1998", result);
 }
@@ -4733,7 +4840,7 @@ void DateFormatTest::TestCreateInstanceForSkeletonWithCalendar() {
         return;
     }
     UnicodeString result;
-    FieldPosition pos(0);
+    FieldPosition pos(FieldPosition::DONT_CARE);
 
     LocalPointer<Calendar> cal(Calendar::createInstance(
         TimeZone::createTimeZone("GMT-7:00"),
@@ -4801,11 +4908,627 @@ void DateFormatTest::TestChangeCalendar() {
         return;
     }
     UnicodeString result;
-    FieldPosition pos(0);
+    FieldPosition pos(FieldPosition::DONT_CARE);
     fmt->format(date(98, 5-1, 25), result, pos);
     assertEquals("format yMMMd", "Iyar 29, 5758", result);
 }
 
+void DateFormatTest::TestPatternFromSkeleton() {
+    static const struct {
+        const Locale& locale;
+        const char* const skeleton;
+        const char* const pattern;
+    } TESTDATA[] = {
+        // Ticket #11985
+        {Locale::getEnglish(), "jjmm", "h:mm a"},
+        {Locale::getEnglish(), "JJmm", "hh:mm"},
+        {Locale::getGerman(), "jjmm", "HH:mm"},
+        {Locale::getGerman(), "JJmm", "HH:mm"}
+    };
+
+    for (size_t i = 0; i < UPRV_LENGTHOF(TESTDATA); i++) {
+        UErrorCode status = U_ZERO_ERROR;
+        LocalPointer<DateFormat> fmt(
+                DateFormat::createInstanceForSkeleton(
+                        TESTDATA[i].skeleton, TESTDATA[i].locale, status));
+        if (!assertSuccess("createInstanceForSkeleton", status)) {
+            return;
+        }
+        UnicodeString pattern;
+        static_cast<const SimpleDateFormat*>(fmt.getAlias())->toPattern(pattern);
+        assertEquals("Format pattern", TESTDATA[i].pattern, pattern);
+    }
+}
+
+void DateFormatTest::TestAmPmMidnightNoon() {
+    // Some times on 2015-11-13 (UTC+0).
+    UDate k000000 = 1447372800000.0;
+    UDate k000030 = 1447372830000.0;
+    UDate k003000 = 1447374600000.0;
+    UDate k060000 = 1447394400000.0;
+    UDate k120000 = 1447416000000.0;
+    UDate k180000 = 1447437600000.0;
+
+    UErrorCode errorCode = U_ZERO_ERROR;
+    SimpleDateFormat sdf(UnicodeString(), errorCode);
+    if (U_FAILURE(errorCode)) {
+        dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
+        return;
+    }
+    const TimeZone *tz = TimeZone::getGMT();
+    sdf.setTimeZone(*tz);
+    UnicodeString out;
+
+    // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
+    // For ICU 57 output of "midnight" is temporarily suppressed.
+
+    // Short.
+    sdf.applyPattern(UnicodeString("hh:mm:ss bbb"));
+
+    // assertEquals("hh:mm:ss bbb | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss bbb | 00:00:00", "12:00:00 AM", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss bbb | 00:00:30", "12:00:30 AM", sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm:ss bbb | 00:30:00", "12:30:00 AM", sdf.format(k003000, out.remove()));
+    assertEquals("hh:mm:ss bbb | 06:00:00", "06:00:00 AM", sdf.format(k060000, out.remove()));
+    assertEquals("hh:mm:ss bbb | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
+    assertEquals("hh:mm:ss bbb | 18:00:00", "06:00:00 PM", sdf.format(k180000, out.remove()));
+
+    sdf.applyPattern(UnicodeString("hh:mm bbb"));
+
+    // assertEquals("hh:mm bbb | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm bbb | 00:00:00", "12:00 AM", sdf.format(k000000, out.remove()));
+    // assertEquals("hh:mm bbb | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm bbb | 00:00:30", "12:00 AM", sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm bbb | 00:30:00", "12:30 AM", sdf.format(k003000, out.remove()));
+
+    sdf.applyPattern(UnicodeString("hh bbb"));
+
+    // assertEquals("hh bbb | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
+    assertEquals("hh bbb | 00:00:00", "12 AM", sdf.format(k000000, out.remove()));
+    // assertEquals("hh bbb | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
+    assertEquals("hh bbb | 00:00:30", "12 AM", sdf.format(k000030, out.remove()));
+    // assertEquals("hh bbb | 00:30:00", "12 midnight", sdf.format(k003000, out.remove()));
+    assertEquals("hh bbb | 00:30:00", "12 AM", sdf.format(k003000, out.remove()));
+
+    // Wide.
+    sdf.applyPattern(UnicodeString("hh:mm:ss bbbb"));
+
+    // assertEquals("hh:mm:ss bbbb | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss bbbb | 00:00:00", "12:00:00 AM", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss bbbb | 00:00:30", "12:00:30 AM", sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm:ss bbbb | 00:30:00", "12:30:00 AM", sdf.format(k003000, out.remove()));
+    assertEquals("hh:mm:ss bbbb | 06:00:00", "06:00:00 AM", sdf.format(k060000, out.remove()));
+    assertEquals("hh:mm:ss bbbb | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
+    assertEquals("hh:mm:ss bbbb | 18:00:00", "06:00:00 PM", sdf.format(k180000, out.remove()));
+
+    sdf.applyPattern(UnicodeString("hh:mm bbbb"));
+
+    // assertEquals("hh:mm bbbb | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm bbbb | 00:00:00", "12:00 AM", sdf.format(k000000, out.remove()));
+    // assertEquals("hh:mm bbbb | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm bbbb | 00:00:30", "12:00 AM", sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm bbbb | 00:30:00", "12:30 AM", sdf.format(k003000, out.remove()));
+
+    sdf.applyPattern(UnicodeString("hh bbbb"));
+
+    // assertEquals("hh bbbb | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
+    assertEquals("hh bbbb | 00:00:00", "12 AM", sdf.format(k000000, out.remove()));
+    // assertEquals("hh bbbb | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
+    assertEquals("hh bbbb | 00:00:30", "12 AM", sdf.format(k000030, out.remove()));
+    // assertEquals("hh bbbb | 00:30:00", "12 midnight", sdf.format(k003000, out.remove()));
+    assertEquals("hh bbbb | 00:30:00", "12 AM", sdf.format(k003000, out.remove()));
+
+    // Narrow.
+    sdf.applyPattern(UnicodeString("hh:mm:ss bbbbb"));
+
+    // assertEquals("hh:mm:ss bbbbb | 00:00:00", "12:00:00 mi", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss bbbbb | 00:00:00", "12:00:00 a", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss bbbbb | 00:00:30", "12:00:30 a", sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm:ss bbbbb | 00:30:00", "12:30:00 a", sdf.format(k003000, out.remove()));
+    assertEquals("hh:mm:ss bbbbb | 06:00:00", "06:00:00 a", sdf.format(k060000, out.remove()));
+    assertEquals("hh:mm:ss bbbbb | 12:00:00", "12:00:00 n", sdf.format(k120000, out.remove()));
+    assertEquals("hh:mm:ss bbbbb | 18:00:00", "06:00:00 p", sdf.format(k180000, out.remove()));
+
+    sdf.applyPattern(UnicodeString("hh:mm bbbbb"));
+
+    // assertEquals("hh:mm bbbbb | 00:00:00", "12:00 mi", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm bbbbb | 00:00:00", "12:00 a", sdf.format(k000000, out.remove()));
+    // assertEquals("hh:mm bbbbb | 00:00:30", "12:00 mi", sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm bbbbb | 00:00:30", "12:00 a", sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm bbbbb | 00:30:00", "12:30 a", sdf.format(k003000, out.remove()));
+
+    sdf.applyPattern(UnicodeString("hh bbbbb"));
+
+    // assertEquals("hh bbbbb | 00:00:00", "12 mi", sdf.format(k000000, out.remove()));
+    assertEquals("hh bbbbb | 00:00:00", "12 a", sdf.format(k000000, out.remove()));
+    // assertEquals("hh bbbbb | 00:00:30", "12 mi", sdf.format(k000030, out.remove()));
+    assertEquals("hh bbbbb | 00:00:30", "12 a", sdf.format(k000030, out.remove()));
+    // assertEquals("hh bbbbb | 00:30:00", "12 mi", sdf.format(k003000, out.remove()));
+    assertEquals("hh bbbbb | 00:30:00", "12 a", sdf.format(k003000, out.remove()));
+}
+
+void DateFormatTest::TestFlexibleDayPeriod() {
+    // Some times on 2015-11-13 (UTC+0).
+    UDate k000000 = 1447372800000.0;
+    UDate k000030 = 1447372830000.0;
+    UDate k003000 = 1447374600000.0;
+    UDate k060000 = 1447394400000.0;
+    UDate k120000 = 1447416000000.0;
+    UDate k180000 = 1447437600000.0;
+
+    UErrorCode errorCode = U_ZERO_ERROR;
+    SimpleDateFormat sdf(UnicodeString(), errorCode);
+    if (U_FAILURE(errorCode)) {
+        dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
+        return;
+    }
+    const TimeZone *tz = TimeZone::getGMT();
+    sdf.setTimeZone(*tz);
+    UnicodeString out;
+
+    // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
+    // For ICU 57 output of "midnight" is temporarily suppressed.
+
+    // Short.
+    sdf.applyPattern(UnicodeString("hh:mm:ss BBB"));
+
+    // assertEquals("hh:mm:ss BBB | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss BBB | 00:00:00", "12:00:00 at night", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss BBB | 00:00:30", "12:00:30 at night", sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm:ss BBB | 00:30:00", "12:30:00 at night", sdf.format(k003000, out.remove()));
+    assertEquals("hh:mm:ss BBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000, out.remove()));
+    assertEquals("hh:mm:ss BBB | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
+    assertEquals("hh:mm:ss BBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000, out.remove()));
+
+    sdf.applyPattern(UnicodeString("hh:mm BBB"));
+
+    // assertEquals("hh:mm BBB | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm BBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
+    // assertEquals("hh:mm BBB | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm BBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm BBB | 00:30:00", "12:30 at night", sdf.format(k003000, out.remove()));
+
+    sdf.applyPattern(UnicodeString("hh BBB"));
+
+    // assertEquals("hh BBB | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
+    assertEquals("hh BBB | 00:00:30", "12 at night", sdf.format(k000030, out.remove()));
+    // assertEquals("hh BBB | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
+    assertEquals("hh BBB | 00:00:30", "12 at night", sdf.format(k000030, out.remove()));
+    // assertEquals("hh BBB | 00:30:00", "12 midnight", sdf.format(k003000, out.remove()));
+    assertEquals("hh BBB | 00:30:00", "12 at night", sdf.format(k003000, out.remove()));
+
+    // Wide.
+    sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
+
+    // assertEquals("hh:mm:ss BBBB | 00:00:00", "12:00:00 midnight", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss BBBB | 00:00:00", "12:00:00 at night", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss BBBB | 00:00:30", "12:00:30 at night", sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm:ss BBBB | 00:30:00", "12:30:00 at night", sdf.format(k003000, out.remove()));
+    assertEquals("hh:mm:ss BBBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000, out.remove()));
+    assertEquals("hh:mm:ss BBBB | 12:00:00", "12:00:00 noon", sdf.format(k120000, out.remove()));
+    assertEquals("hh:mm:ss BBBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000, out.remove()));
+
+    sdf.applyPattern(UnicodeString("hh:mm BBBB"));
+
+    // assertEquals("hh:mm BBBB | 00:00:00", "12:00 midnight", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm BBBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
+    // assertEquals("hh:mm BBBB | 00:00:30", "12:00 midnight", sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm BBBB | 00:00:30", "12:00 at night", sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm BBBB | 00:30:00", "12:30 at night", sdf.format(k003000, out.remove()));
+
+    sdf.applyPattern(UnicodeString("hh BBBB"));
+
+    // assertEquals("hh BBBB | 00:00:00", "12 midnight", sdf.format(k000000, out.remove()));
+    assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
+    // assertEquals("hh BBBB | 00:00:30", "12 midnight", sdf.format(k000030, out.remove()));
+    assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
+    // assertEquals("hh BBBB | 00:80:00", "12 midnight", sdf.format(k003000, out.remove()));
+    assertEquals("hh BBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
+
+    // Narrow.
+    sdf.applyPattern(UnicodeString("hh:mm:ss BBBBB"));
+
+    // assertEquals("hh:mm:ss BBBBB | 00:00:00", "12:00:00 mi", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss BBBBB | 00:00:00", "12:00:00 at night", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss BBBBB | 00:00:30", "12:00:30 at night", sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm:ss BBBBB | 00:30:00", "12:30:00 at night", sdf.format(k003000, out.remove()));
+    assertEquals("hh:mm:ss BBBBB | 06:00:00", "06:00:00 in the morning", sdf.format(k060000, out.remove()));
+    assertEquals("hh:mm:ss BBBBB | 12:00:00", "12:00:00 n", sdf.format(k120000, out.remove()));
+    assertEquals("hh:mm:ss BBBBB | 18:00:00", "06:00:00 in the evening", sdf.format(k180000, out.remove()));
+
+    sdf.applyPattern(UnicodeString("hh:mm BBBBB"));
+
+    // assertEquals("hh:mm BBBBB | 00:00:00", "12:00 mi", sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm BBBBB | 00:00:00", "12:00 at night", sdf.format(k000000, out.remove()));
+    // assertEquals("hh:mm BBBBB | 00:00:30", "12:00 mi", sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm BBBBB | 00:00:30", "12:00 at night", sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm BBBBB | 00:30:00", "12:30 at night", sdf.format(k003000, out.remove()));
+
+    sdf.applyPattern(UnicodeString("hh BBBBB"));
+
+    // assertEquals("hh BBBBB | 00:00:00", "12 mi", sdf.format(k000000, out.remove()));
+    assertEquals("hh BBBBB | 00:00:00", "12 at night", sdf.format(k000000, out.remove()));
+    // assertEquals("hh BBBBB | 00:00:30", "12 mi", sdf.format(k000030, out.remove()));
+    assertEquals("hh BBBBB | 00:00:30", "12 at night", sdf.format(k000030, out.remove()));
+    // assertEquals("hh BBBBB | 00:30:00", "12 mi", sdf.format(k003000, out.remove()));
+    assertEquals("hh BBBBB | 00:30:00", "12 at night", sdf.format(k003000, out.remove()));
+}
+
+void DateFormatTest::TestDayPeriodWithLocales() {
+    // Some times on 2015-11-13 (UTC+0).
+    UDate k000000 = 1447372800000.0;
+    UDate k010000 = 1447376400000.0;
+    UDate k120000 = 1447416000000.0;
+    UDate k220000 = 1447452000000.0;
+
+    UErrorCode errorCode = U_ZERO_ERROR;
+    const TimeZone *tz = TimeZone::getGMT();
+    UnicodeString out;
+
+    // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
+    // For ICU 57 output of "midnight" and its localized equivalentns is temporarily suppressed.
+
+    // Locale de has a word for midnight, but not noon.
+    SimpleDateFormat sdf(UnicodeString(), Locale::getGermany(), errorCode);
+    if (U_FAILURE(errorCode)) {
+        dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
+        return;
+    }
+    sdf.setTimeZone(*tz);
+
+    sdf.applyPattern(UnicodeString("hh:mm:ss bbbb"));
+
+    // assertEquals("hh:mm:ss bbbb | 00:00:00 | de", "12:00:00 Mitternacht",
+    //     sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss bbbb | 00:00:00 | de", "12:00:00 AM" /* change for Apple data */,
+        sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss bbbb | 12:00:00 | de", "12:00:00 PM" /* change for Apple data */,
+        sdf.format(k120000, out.remove()));
+
+    // Locale ee has a rule that wraps around midnight (21h - 4h).
+    sdf = SimpleDateFormat(UnicodeString(), Locale("ee"), errorCode);
+    sdf.setTimeZone(*tz);
+
+    sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
+
+    assertEquals("hh:mm:ss BBBB | 22:00:00 | ee", UnicodeString("10:00:00 z\\u00E3").unescape(),
+        sdf.format(k220000, out.remove()));
+    assertEquals("hh:mm:ss BBBB | 00:00:00 | ee", UnicodeString("12:00:00 z\\u00E3").unescape(),
+        sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss BBBB | 01:00:00 | ee", UnicodeString("01:00:00 z\\u00E3").unescape(),
+        sdf.format(k010000, out.remove()));
+
+    // Locale root has rules for AM/PM only.
+    sdf = SimpleDateFormat(UnicodeString(), Locale("root"), errorCode);
+    sdf.setTimeZone(*tz);
+
+    sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
+
+    assertEquals("hh:mm:ss BBBB | 00:00:00 | root", "12:00:00 AM",
+        sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss BBBB | 12:00:00 | root", "12:00:00 PM",
+        sdf.format(k120000, out.remove()));
+
+    // Empty string should behave exactly as root.
+    sdf = SimpleDateFormat(UnicodeString(), Locale(""), errorCode);
+    sdf.setTimeZone(*tz);
+
+    sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
+
+    assertEquals("hh:mm:ss BBBB | 00:00:00 | \"\" (root)", "12:00:00 AM",
+        sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss BBBB | 12:00:00 | \"\" (root)", "12:00:00 PM",
+        sdf.format(k120000, out.remove()));
+
+    // Locale en_US should fall back to en.
+    sdf = SimpleDateFormat(UnicodeString(), Locale("en_US"), errorCode);
+    sdf.setTimeZone(*tz);
+
+    sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
+
+    // assertEquals("hh:mm:ss BBBB | 00:00:00 | en_US", "12:00:00 midnight",
+    //     sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss BBBB | 00:00:00 | en_US", "12:00:00 at night",
+         sdf.format(k000000, out.remove()));
+    assertEquals("hh:mm:ss BBBB | 01:00:00 | en_US", "01:00:00 at night",
+        sdf.format(k010000, out.remove()));
+    assertEquals("hh:mm:ss BBBB | 12:00:00 | en_US", "12:00:00 noon",
+        sdf.format(k120000, out.remove()));
+
+    // Locale es_CO should not fall back to es and should have a
+    // different string for 1 in the morning.
+    // (es_CO: "de la manana" (first n has a tilde) vs. es: "de la madrugada")
+    sdf = SimpleDateFormat(UnicodeString(), Locale("es_CO"), errorCode);
+    sdf.setTimeZone(*tz);
+
+    sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
+    assertEquals("hh:mm:ss BBBB | 01:00:00 | es_CO", UnicodeString("01:00:00 de la ma\\u00F1ana").unescape(),
+        sdf.format(k010000, out.remove()));
+
+    sdf = SimpleDateFormat(UnicodeString(), Locale("es"), errorCode);
+    sdf.setTimeZone(*tz);
+
+    sdf.applyPattern(UnicodeString("hh:mm:ss BBBB"));
+    assertEquals("hh:mm:ss BBBB | 01:00:00 | es", "01:00:00 de la madrugada",
+        sdf.format(k010000, out.remove()));
+}
+
+void DateFormatTest::TestMinuteSecondFieldsInOddPlaces() {
+    // Some times on 2015-11-13 (UTC+0).
+    UDate k000000 = 1447372800000.0;
+    UDate k000030 = 1447372830000.0;
+    UDate k003000 = 1447374600000.0;
+    UDate k060030 = 1447394430000.0;
+    UDate k063000 = 1447396200000.0;
+
+    UErrorCode errorCode = U_ZERO_ERROR;
+    const TimeZone *tz = TimeZone::getGMT();
+    UnicodeString out;
+
+    // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
+    // For ICU 57 output of "midnight" is temporarily suppressed.
+
+    // Seconds field is not present.
+
+    // Apply pattern through constructor to make sure parsePattern() is called during initialization.
+    SimpleDateFormat sdf(UnicodeString("hh:mm 'ss' bbbb"), errorCode);
+    if (U_FAILURE(errorCode)) {
+        dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
+        return;
+    }
+    sdf.setTimeZone(*tz);
+
+    // assertEquals("hh:mm 'ss' bbbb | 00:00:30", "12:00 ss midnight",
+    //     sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm 'ss' bbbb | 00:00:30", "12:00 ss AM",
+        sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm 'ss' bbbb | 06:00:30", "06:00 ss AM",
+        sdf.format(k060030, out.remove()));
+
+    sdf.applyPattern(UnicodeString("hh:mm 'ss' BBBB"));
+
+    // assertEquals("hh:mm 'ss' BBBB | 00:00:30", "12:00 ss midnight",
+    //     sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm 'ss' BBBB | 00:00:30", "12:00 ss at night",
+        sdf.format(k000030, out.remove()));
+    assertEquals("hh:mm 'ss' BBBB | 06:00:30", "06:00 ss in the morning",
+        sdf.format(k060030, out.remove()));
+
+    // Minutes field is not present.
+    sdf.applyPattern(UnicodeString("hh 'mm ss' bbbb"));
+
+    // assertEquals("hh 'mm ss' bbbb | 00:30:00", "12 mm ss midnight",
+    //     sdf.format(k003000, out.remove()));
+    assertEquals("hh 'mm ss' bbbb | 00:30:00", "12 mm ss AM",
+        sdf.format(k003000, out.remove()));
+    assertEquals("hh 'mm ss' bbbb | 06:30:00", "06 mm ss AM",
+        sdf.format(k063000, out.remove()));
+
+    sdf.applyPattern(UnicodeString("hh 'mm ss' BBBB"));
+
+    // assertEquals("hh 'mm ss' BBBB | 00:30:00", "12 mm ss midnight",
+    //     sdf.format(k003000, out.remove()));
+    assertEquals("hh 'mm ss' BBBB | 00:30:00", "12 mm ss at night",
+        sdf.format(k003000, out.remove()));
+    assertEquals("hh 'mm ss' BBBB | 06:30:00", "06 mm ss in the morning",
+        sdf.format(k063000, out.remove()));
+
+    // Minutes and seconds fields appear after day periods.
+    sdf.applyPattern(UnicodeString("bbbb hh:mm:ss"));
+
+    // assertEquals("bbbb hh:mm:ss | 00:00:00", "midnight 12:00:00",
+    //     sdf.format(k000000, out.remove()));
+    assertEquals("bbbb hh:mm:ss | 00:00:00", "AM 12:00:00",
+        sdf.format(k000000, out.remove()));
+    assertEquals("bbbb hh:mm:ss | 00:00:30", "AM 12:00:30",
+        sdf.format(k000030, out.remove()));
+    assertEquals("bbbb hh:mm:ss | 00:30:00", "AM 12:30:00",
+        sdf.format(k003000, out.remove()));
+
+    sdf.applyPattern(UnicodeString("BBBB hh:mm:ss"));
+
+    // assertEquals("BBBB hh:mm:ss | 00:00:00", "midnight 12:00:00",
+    //     sdf.format(k000000, out.remove()));
+    assertEquals("BBBB hh:mm:ss | 00:00:00", "at night 12:00:00",
+        sdf.format(k000000, out.remove()));
+    assertEquals("BBBB hh:mm:ss | 00:00:30", "at night 12:00:30",
+        sdf.format(k000030, out.remove()));
+    assertEquals("BBBB hh:mm:ss | 00:30:00", "at night 12:30:00",
+        sdf.format(k003000, out.remove()));
+
+    // Confirm applyPattern() reparses the pattern string.
+    sdf.applyPattern(UnicodeString("BBBB hh"));
+    // assertEquals("BBBB hh | 00:00:30", "midnight 12",
+    //     sdf.format(k000030, out.remove()));
+    assertEquals("BBBB hh | 00:00:30", "at night 12",
+         sdf.format(k000030, out.remove()));
+
+    sdf.applyPattern(UnicodeString("BBBB hh:mm:'ss'"));
+    // assertEquals("BBBB hh:mm:'ss' | 00:00:30", "midnight 12:00:ss",
+    //     sdf.format(k000030, out.remove()));
+    assertEquals("BBBB hh | 00:00:30", "at night 12:00:ss",
+        sdf.format(k000030, out.remove()));
+
+    sdf.applyPattern(UnicodeString("BBBB hh:mm:ss"));
+    assertEquals("BBBB hh:mm:ss | 00:00:30", "at night 12:00:30",
+        sdf.format(k000030, out.remove()));
+}
+
+void DateFormatTest::TestDayPeriodParsing() {
+    // Some times on 2015-11-13 (UTC+0).
+    UDate k000000 = 1447372800000.0;
+    UDate k003700 = 1447375020000.0;
+    UDate k010000 = 1447376400000.0;
+    UDate k013000 = 1447378200000.0;
+    UDate k030000 = 1447383600000.0;
+    UDate k090000 = 1447405200000.0;
+    UDate k120000 = 1447416000000.0;
+    UDate k130000 = 1447419600000.0;
+    UDate k133700 = 1447421820000.0;
+    UDate k150000 = 1447426800000.0;
+    UDate k190000 = 1447441200000.0;
+    UDate k193000 = 1447443000000.0;
+    UDate k200000 = 1447444800000.0;
+    UDate k210000 = 1447448400000.0;
+
+    UErrorCode errorCode = U_ZERO_ERROR;
+    SimpleDateFormat sdf(UnicodeString(), errorCode);
+    if (U_FAILURE(errorCode)) {
+        dataerrln("Error creating SimpleDateFormat - %s", u_errorName(errorCode));
+        return;
+    }
+    const TimeZone *tz = TimeZone::getGMT();
+    sdf.setTimeZone(*tz);
+    UnicodeString out;
+
+    // 'B' -- flexible day periods
+    // A day period on its own parses to the center of that period.
+    sdf.applyPattern(UnicodeString("yyyy-MM-dd B"));
+    assertEquals("yyyy-MM-dd B | 2015-11-13 midnight",
+        k000000, sdf.parse(UnicodeString("2015-11-13 midnight"), errorCode));
+    assertEquals("yyyy-MM-dd B | 2015-11-13 noon",
+        k120000, sdf.parse(UnicodeString("2015-11-13 noon"), errorCode));
+    assertEquals("yyyy-MM-dd B | 2015-11-13 in the afternoon",
+        k150000, sdf.parse(UnicodeString("2015-11-13 in the afternoon"), errorCode));
+    assertEquals("yyyy-MM-dd B | 2015-11-13 in the evening",
+        k193000, sdf.parse(UnicodeString("2015-11-13 in the evening"), errorCode));
+    assertEquals("yyyy-MM-dd B | 2015-11-13 at night",
+        k013000, sdf.parse(UnicodeString("2015-11-13 at night"), errorCode));
+
+    // If time and day period are consistent with each other then time is parsed accordingly.
+    sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm B"));
+    assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 12:00 midnight",
+        k000000, sdf.parse(UnicodeString("2015-11-13 12:00 midnight"), errorCode));
+    assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 12:00 noon",
+        k120000, sdf.parse(UnicodeString("2015-11-13 12:00 noon"), errorCode));
+    assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 01:00 at night",
+        k010000, sdf.parse(UnicodeString("2015-11-13 01:00 at night"), errorCode));
+    assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 01:00 in the afternoon",
+        k130000, sdf.parse(UnicodeString("2015-11-13 01:00 in the afternoon"), errorCode));
+    assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 09:00 in the morning",
+        k090000, sdf.parse(UnicodeString("2015-11-13 09:00 in the morning"), errorCode));
+    assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 09:00 at night",
+        k210000, sdf.parse(UnicodeString("2015-11-13 09:00 at night"), errorCode));
+
+    // If the hour is 13 thru 23 then day period has no effect on time (since time is assumed
+    // to be in 24-hour format).
+    sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm B"));
+    assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 midnight",
+        k133700, sdf.parse(UnicodeString("2015-11-13 13:37 midnight"), errorCode));
+    assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 noon",
+        k133700, sdf.parse(UnicodeString("2015-11-13 13:37 noon"), errorCode));
+    assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 at night",
+        k133700, sdf.parse(UnicodeString("2015-11-13 13:37 at night"), errorCode));
+    assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 in the afternoon",
+        k133700, sdf.parse(UnicodeString("2015-11-13 13:37 in the afternoon"), errorCode));
+    assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 in the morning",
+        k133700, sdf.parse(UnicodeString("2015-11-13 13:37 in the morning"), errorCode));
+    assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 13:37 at night",
+        k133700, sdf.parse(UnicodeString("2015-11-13 13:37 at night"), errorCode));
+
+    // Hour 0 is synonymous with hour 12 when parsed with 'h'.
+    // This unfortunately means we have to tolerate "0 noon" as it's synonymous with "12 noon".
+    sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm B"));
+    assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 00:00 midnight",
+        k000000, sdf.parse(UnicodeString("2015-11-13 00:00 midnight"), errorCode));
+    assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 00:00 noon",
+        k120000, sdf.parse(UnicodeString("2015-11-13 00:00 noon"), errorCode));
+
+    // But when parsed with 'H', 0 indicates a 24-hour time, therefore we disregard the day period.
+    sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm B"));
+    assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 midnight",
+        k003700, sdf.parse(UnicodeString("2015-11-13 00:37 midnight"), errorCode));
+    assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 noon",
+        k003700, sdf.parse(UnicodeString("2015-11-13 00:37 noon"), errorCode));
+    assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 at night",
+        k003700, sdf.parse(UnicodeString("2015-11-13 00:37 at night"), errorCode));
+    assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 in the afternoon",
+        k003700, sdf.parse(UnicodeString("2015-11-13 00:37 in the afternoon"), errorCode));
+    assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 in the morning",
+        k003700, sdf.parse(UnicodeString("2015-11-13 00:37 in the morning"), errorCode));
+    assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 00:37 at night",
+        k003700, sdf.parse(UnicodeString("2015-11-13 00:37 at night"), errorCode));
+
+    // Even when parsed with 'H', hours 1 thru 12 are considered 12-hour time and takes
+    // day period into account in parsing.
+    sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm B"));
+    assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 12:00 midnight",
+        k000000, sdf.parse(UnicodeString("2015-11-13 12:00 midnight"), errorCode));
+    assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 12:00 noon",
+        k120000, sdf.parse(UnicodeString("2015-11-13 12:00 noon"), errorCode));
+    assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 01:00 at night",
+        k010000, sdf.parse(UnicodeString("2015-11-13 01:00 at night"), errorCode));
+    assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 01:00 in the afternoon",
+        k130000, sdf.parse(UnicodeString("2015-11-13 01:00 in the afternoon"), errorCode));
+    assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 09:00 in the morning",
+        k090000, sdf.parse(UnicodeString("2015-11-13 09:00 in the morning"), errorCode));
+    assertEquals("yyyy-MM-dd HH:mm B | 2015-11-13 09:00 at night",
+        k210000, sdf.parse(UnicodeString("2015-11-13 09:00 at night"), errorCode));
+
+    // If a 12-hour time and the day period don't agree with each other, time is parsed as close
+    // to the given day period as possible.
+    sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm B"));
+
+    // AFTERNOON1 is [12, 18), but "7 in the afternoon" parses to 19:00.
+    assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 07:00 in the afternoon",
+        k190000, sdf.parse(UnicodeString("2015-11-13 07:00 in the afternoon"), errorCode));
+    // NIGHT1 is [21, 6), but "8 at night" parses to 20:00.
+    assertEquals("yyyy-MM-dd hh:mm B | 2015-11-13 08:00 at night",
+        k200000, sdf.parse(UnicodeString("2015-11-13 08:00 at night"), errorCode));
+
+    // 'b' -- fixed day periods (AM, PM, midnight, noon)
+    // On their own, "midnight" parses to 00:00 and "noon" parses to 12:00.
+    // AM and PM are handled by the 'a' parser (which doesn't handle this case well).
+    sdf.applyPattern(UnicodeString("yyyy-MM-dd b"));
+    assertEquals("yyyy-MM-dd b | 2015-11-13 midnight",
+        k000000, sdf.parse(UnicodeString("2015-11-13 midnight"), errorCode));
+    assertEquals("yyyy-MM-dd b | 2015-11-13 noon",
+        k120000, sdf.parse(UnicodeString("2015-11-13 noon"), errorCode));
+
+    // For 12-hour times, AM and PM should be parsed as if with pattern character 'a'.
+    sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm b"));
+    assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 01:00 AM",
+        k010000, sdf.parse(UnicodeString("2015-11-13 01:00 AM"), errorCode));
+    assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 01:00 PM",
+        k130000, sdf.parse(UnicodeString("2015-11-13 01:00 PM"), errorCode));
+
+    // 12 midnight parses to 00:00, and 12 noon parses to 12:00.
+    assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 12:00 midnight",
+        k000000, sdf.parse(UnicodeString("2015-11-13 12:00 midnight"), errorCode));
+    assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 12:00 noon",
+        k120000, sdf.parse(UnicodeString("2015-11-13 12:00 noon"), errorCode));
+
+    // Hours 13-23 indicate 24-hour time so we disregard "midnight" or "noon".
+    // Again, AM and PM are handled by the 'a' parser which doesn't handle this case well.
+    sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm b"));
+    assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 13:37 midnight",
+        k133700, sdf.parse(UnicodeString("2015-11-13 13:37 midnight"), errorCode));
+    assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 13:37 noon",
+        k133700, sdf.parse(UnicodeString("2015-11-13 13:37 noon"), errorCode));
+
+    // Hour 0 is synonymous with hour 12 when parsed with 'h'.
+    // Again, this means we have to tolerate "0 noon" as it's synonymous with "12 noon".
+    sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm b"));
+    assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 00:00 midnight",
+        k000000, sdf.parse(UnicodeString("2015-11-13 00:00 midnight"), errorCode));
+    assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 00:00 noon",
+        k120000, sdf.parse(UnicodeString("2015-11-13 00:00 noon"), errorCode));
+
+    // With 'H' though 0 indicates a 24-hour time, therefore we disregard the day period.
+    sdf.applyPattern(UnicodeString("yyyy-MM-dd HH:mm b"));
+    assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 00:37 midnight",
+        k003700, sdf.parse(UnicodeString("2015-11-13 00:37 midnight"), errorCode));
+    assertEquals("yyyy-MM-dd HH:mm b | 2015-11-13 00:37 noon",
+        k003700, sdf.parse(UnicodeString("2015-11-13 00:37 noon"), errorCode));
+
+    // If "midnight" or "noon" is parsed with a 12-hour time other than 12:00, choose
+    // the version that's closer to the period given.
+    sdf.applyPattern(UnicodeString("yyyy-MM-dd hh:mm b"));
+    assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 03:00 midnight",
+        k030000, sdf.parse(UnicodeString("2015-11-13 03:00 midnight"), errorCode));
+    assertEquals("yyyy-MM-dd hh:mm b | 2015-11-13 03:00 noon",
+        k150000, sdf.parse(UnicodeString("2015-11-13 03:00 noon"), errorCode));
+}
 
 #endif /* #if !UCONFIG_NO_FORMATTING */