Merge "Remove invalid X509Certificate2Test tests"
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index eafa40d..98de1f2 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -167,19 +167,19 @@
 #
 #
 # Run with:
-#     m libcore-docs
+#     mm -j32 libcore-docs
 #
 # Main output:
-#     out/target/common/docs/libcore/reference/packages.html
+#     ../out/target/common/docs/libcore/reference/packages.html
 #
 # All text for proofreading (or running tools over):
-#     out/target/common/docs/libcore-proofread.txt
+#     ../out/target/common/docs/libcore-proofread.txt
 #
 # TODO list of missing javadoc, etc:
-#     out/target/common/docs/libcore-docs-todo.html
+#     ../out/target/common/docs/libcore-docs-todo.html
 #
 # Rerun:
-#     rm -rf out/target/common/docs/libcore-timestamp && m libcore-docs
+#     rm -rf ../out/target/common/docs/libcore-timestamp && mm -j32 libcore-docs
 #
 include $(CLEAR_VARS)
 
diff --git a/include/ScopedPrimitiveArray.h b/include/ScopedPrimitiveArray.h
index 079e98c..f6626b2 100644
--- a/include/ScopedPrimitiveArray.h
+++ b/include/ScopedPrimitiveArray.h
@@ -40,6 +40,7 @@
             } \
         } \
         const PRIMITIVE_TYPE* get() const { return mRawArray; } \
+        PRIMITIVE_TYPE ## Array getJavaArray() const { return mJavaArray; } \
         const PRIMITIVE_TYPE& operator[](size_t n) const { return mRawArray[n]; } \
         size_t size() const { return mEnv->GetArrayLength(mJavaArray); } \
     private: \
@@ -82,6 +83,7 @@
             } \
         } \
         const PRIMITIVE_TYPE* get() const { return mRawArray; } \
+        PRIMITIVE_TYPE ## Array getJavaArray() const { return mJavaArray; } \
         const PRIMITIVE_TYPE& operator[](size_t n) const { return mRawArray[n]; } \
         PRIMITIVE_TYPE* get() { return mRawArray; } \
         PRIMITIVE_TYPE& operator[](size_t n) { return mRawArray[n]; } \
diff --git a/luni/src/main/java/java/text/DateFormatSymbols.java b/luni/src/main/java/java/text/DateFormatSymbols.java
index 6049fd2..d14f309c 100644
--- a/luni/src/main/java/java/text/DateFormatSymbols.java
+++ b/luni/src/main/java/java/text/DateFormatSymbols.java
@@ -58,11 +58,8 @@
 
     String[] ampms, eras, months, shortMonths, shortWeekdays, weekdays;
 
-    // These are used to implement ICU/Android extensions.
-    transient String[] longStandAloneMonths;
-    transient String[] shortStandAloneMonths;
-    transient String[] longStandAloneWeekdays;
-    transient String[] shortStandAloneWeekdays;
+    // This is used to implement parts of Unicode UTS #35 not historically supported.
+    transient LocaleData localeData;
 
     // Localized display names.
     String[][] zoneStrings;
@@ -107,19 +104,14 @@
     public DateFormatSymbols(Locale locale) {
         this.locale = locale;
         this.localPatternChars = SimpleDateFormat.PATTERN_CHARS;
-        LocaleData localeData = LocaleData.get(locale);
+
+        this.localeData = LocaleData.get(locale);
         this.ampms = localeData.amPm;
         this.eras = localeData.eras;
         this.months = localeData.longMonthNames;
         this.shortMonths = localeData.shortMonthNames;
         this.weekdays = localeData.longWeekdayNames;
         this.shortWeekdays = localeData.shortWeekdayNames;
-
-        // ICU/Android extensions.
-        this.longStandAloneMonths = localeData.longStandAloneMonthNames;
-        this.shortStandAloneMonths = localeData.shortStandAloneMonthNames;
-        this.longStandAloneWeekdays = localeData.longStandAloneWeekdayNames;
-        this.shortStandAloneWeekdays = localeData.shortStandAloneWeekdayNames;
     }
 
     /**
@@ -160,12 +152,7 @@
 
     private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
         ois.defaultReadObject();
-
-        // The RI doesn't have these fields, so we'll have to fall back and do the best we can.
-        longStandAloneMonths = months;
-        shortStandAloneMonths = shortMonths;
-        longStandAloneWeekdays = weekdays;
-        shortStandAloneWeekdays = shortWeekdays;
+        this.localeData = LocaleData.get(locale);
     }
 
     private void writeObject(ObjectOutputStream oos) throws IOException {
diff --git a/luni/src/main/java/java/text/SimpleDateFormat.java b/luni/src/main/java/java/text/SimpleDateFormat.java
index e8aea4a..6d225c6 100644
--- a/luni/src/main/java/java/text/SimpleDateFormat.java
+++ b/luni/src/main/java/java/text/SimpleDateFormat.java
@@ -33,12 +33,12 @@
 import libcore.icu.TimeZones;
 
 /**
- * A concrete class for formatting and parsing dates in a locale-sensitive
- * manner. Formatting turns a {@link Date} into a {@link String}, and parsing turns a
- * {@code String} into a {@code Date}.
+ * Formats and parses dates in a locale-sensitive manner. Formatting turns a {@link Date} into
+ * a {@link String}, and parsing turns a {@code String} into a {@code Date}.
  *
  * <h4>Time Pattern Syntax</h4>
- * <p>You can supply a pattern describing what strings are produced/accepted, but almost all
+ * <p>You can supply a Unicode <a href="http://www.unicode.org/reports/tr35/#Date_Format_Patterns">UTS #35</a>
+ * pattern describing what strings are produced/accepted, but almost all
  * callers should use {@link DateFormat#getDateInstance}, {@link DateFormat#getDateTimeInstance},
  * or {@link DateFormat#getTimeInstance} to get a ready-made instance suitable for the user's
  * locale.
@@ -57,62 +57,46 @@
  * of the ASCII letters is given in the table below. ASCII letters not appearing in the table are
  * reserved for future use, and it is an error to attempt to use them.
  *
+ * <p>The number of consecutive copies (the "count") of a pattern character further influences
+ * the format, as shown in the table. For fields of kind "number", the count is the minimum number
+ * of digits; shorter values are zero-padded to the given width and longer values overflow it.
+ *
  * <p><table BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
  * <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
- *      <td><B>Symbol</B></td> <td><B>Meaning</B></td> <td><B>Presentation</B></td> <td><B>Example</B></td> </tr>
+ *      <td><B>Symbol</B></td> <td><B>Meaning</B></td> <td><B>Kind</B></td> <td><B>Example</B></td> </tr>
  * <tr> <td>{@code D}</td> <td>day in year</td>             <td>(Number)</td>      <td>189</td> </tr>
- * <tr> <td>{@code E}</td> <td>day of week</td>             <td>(Text)</td>        <td>Tuesday</td> </tr>
+ * <tr> <td>{@code E}</td> <td>day of week</td>             <td>(Text)</td>        <td>{@code E}/{@code EE}/{@code EEE}:Tue, {@code EEEE}:Tuesday, {@code EEEEE}:T</td> </tr>
  * <tr> <td>{@code F}</td> <td>day of week in month</td>    <td>(Number)</td>      <td>2 <i>(2nd Wed in July)</i></td> </tr>
  * <tr> <td>{@code G}</td> <td>era designator</td>          <td>(Text)</td>        <td>AD</td> </tr>
  * <tr> <td>{@code H}</td> <td>hour in day (0-23)</td>      <td>(Number)</td>      <td>0</td> </tr>
  * <tr> <td>{@code K}</td> <td>hour in am/pm (0-11)</td>    <td>(Number)</td>      <td>0</td> </tr>
- * <tr> <td>{@code L}</td> <td>stand-alone month</td>       <td>(Text/Number)</td> <td>July / 07</td> </tr>
- * <tr> <td>{@code M}</td> <td>month in year</td>           <td>(Text/Number)</td> <td>July / 07</td> </tr>
+ * <tr> <td>{@code L}</td> <td>stand-alone month</td>       <td>(Text)</td>        <td>{@code L}:1 {@code LL}:01 {@code LLL}:Jan {@code LLLL}:January {@code LLLLL}:J</td> </tr>
+ * <tr> <td>{@code M}</td> <td>month in year</td>           <td>(Text)</td>        <td>{@code M}:1 {@code MM}:01 {@code MMM}:Jan {@code MMMM}:January {@code MMMMM}:J</td> </tr>
  * <tr> <td>{@code S}</td> <td>fractional seconds</td>      <td>(Number)</td>      <td>978</td> </tr>
  * <tr> <td>{@code W}</td> <td>week in month</td>           <td>(Number)</td>      <td>2</td> </tr>
- * <tr> <td>{@code Z}</td> <td>time zone (RFC 822)</td>     <td>(Timezone)</td>    <td>-0800</td> </tr>
+ * <tr> <td>{@code Z}</td> <td>time zone (RFC 822)</td>     <td>(Time Zone)</td>   <td>{@code Z}/{@code ZZ}/{@code ZZZ}:-0800 {@code ZZZZ}:GMT-08:00 {@code ZZZZZ}:-08:00</td> </tr>
  * <tr> <td>{@code a}</td> <td>am/pm marker</td>            <td>(Text)</td>        <td>PM</td> </tr>
- * <tr> <td>{@code c}</td> <td>stand-alone day of week</td> <td>(Text/Number)</td> <td>Tuesday / 2</td> </tr>
+ * <tr> <td>{@code c}</td> <td>stand-alone day of week</td> <td>(Text)</td>        <td>{@code c}/{@code cc}/{@code ccc}:Tue, {@code cccc}:Tuesday, {@code ccccc}:T</td> </tr>
  * <tr> <td>{@code d}</td> <td>day in month</td>            <td>(Number)</td>      <td>10</td> </tr>
  * <tr> <td>{@code h}</td> <td>hour in am/pm (1-12)</td>    <td>(Number)</td>      <td>12</td> </tr>
  * <tr> <td>{@code k}</td> <td>hour in day (1-24)</td>      <td>(Number)</td>      <td>24</td> </tr>
  * <tr> <td>{@code m}</td> <td>minute in hour</td>          <td>(Number)</td>      <td>30</td> </tr>
  * <tr> <td>{@code s}</td> <td>second in minute</td>        <td>(Number)</td>      <td>55</td> </tr>
  * <tr> <td>{@code w}</td> <td>week in year</td>            <td>(Number)</td>      <td>27</td> </tr>
- * <tr> <td>{@code y}</td> <td>year</td>                    <td>(Number)</td>      <td>2010</td> </tr>
- * <tr> <td>{@code z}</td> <td>time zone</td>               <td>(Timezone)</td>    <td>Pacific Standard Time</td> </tr>
- * <tr> <td>{@code '}</td> <td>escape for text</td>         <td>(Delimiter)</td>   <td>'Date='</td> </tr>
- * <tr> <td>{@code ''}</td> <td>single quote</td>           <td>(Literal)</td>     <td>'o''clock'</td> </tr>
+ * <tr> <td>{@code y}</td> <td>year</td>                    <td>(Number)</td>      <td>{@code yy}:10 {@code y}/{@code yyy}/{@code yyyy}:2010</td> </tr>
+ * <tr> <td>{@code z}</td> <td>time zone</td>               <td>(Time Zone)</td>   <td>{@code z}/{@code zz}/{@code zzz}:PST {@code ZZZZ}:Pacific Standard Time</td> </tr>
+ * <tr> <td>{@code '}</td> <td>escape for text</td>         <td>(Delimiter)</td>   <td>{@code 'Date='}:Date=</td> </tr>
+ * <tr> <td>{@code ''}</td> <td>single quote</td>           <td>(Literal)</td>     <td>{@code 'o''clock'}:o'clock</td> </tr>
  * </table>
  *
- * <p>The number of consecutive copies (the "count") of a pattern character further influences
- * the format.
- * <ul>
- * <li><b>Text</b> if the count is 4 or more, use the full form; otherwise use a short or
- * abbreviated form if one exists. So {@code zzzz} might give {@code Pacific Standard Time}
- * whereas {@code z} might give {@code PST}. Note that the count does <i>not</i> specify the
- * exact width of the field.
- *
- * <li><b>Number</b> the count is the minimum number of digits. Shorter values are
- * zero-padded to this width, longer values overflow this width.
- *
- * <p>Years are handled specially: {@code yy} truncates to the last 2 digits, but any
- * other number of consecutive {@code y}s does not truncate. So where {@code yyyy} or
- * {@code y} might give {@code 2010}, {@code yy} would give {@code 10}.
- *
- * <p>Fractional seconds are also handled specially: they're zero-padded on the
- * <i>right</i>.
- *
- * <li><b>Text/Number</b>: if the count is 3 or more, use text; otherwise use a number.
- * So {@code MM} might give {@code 07} while {@code MMM} gives {@code July}.
- * </ul>
+ * <p>Fractional seconds are handled specially: they're zero-padded on the <i>right</i>.
  *
  * <p>The two pattern characters {@code L} and {@code c} are ICU-compatible extensions, not
  * available in the RI or in Android before Android 2.3 "Gingerbread" (API level 9). These
  * extensions are necessary for correct localization in languages such as Russian
  * that distinguish between, say, "June" and "June 2010".
  *
- * <p>When numeric fields are adjacent directly, with no intervening delimiter
+ * <p>When two numeric fields are directly adjacent with no intervening delimiter
  * characters, they constitute a run of adjacent numeric fields. Such runs are
  * parsed specially. For example, the format "HHmmss" parses the input text
  * "123456" to 12:34:56, parses the input text "12345" to 1:23:45, and fails to
@@ -529,8 +513,7 @@
      *            if the object cannot be formatted by this Format.
      */
     private StringBuffer formatImpl(Date date, StringBuffer buffer,
-            FieldPosition field, List<FieldPosition> fields) {
-
+                                    FieldPosition field, List<FieldPosition> fields) {
         boolean quote = false;
         int next, last = -1, count = 0;
         calendar.setTime(date);
@@ -610,24 +593,24 @@
                     appendNumber(buffer, count, year);
                 }
                 break;
-            case STAND_ALONE_MONTH_FIELD: // L
+            case STAND_ALONE_MONTH_FIELD: // 'L'
                 dateFormatField = Field.MONTH;
-                appendMonth(buffer, count, formatData.longStandAloneMonths, formatData.shortStandAloneMonths);
+                appendMonth(buffer, count, true);
                 break;
-            case MONTH_FIELD: // M
+            case MONTH_FIELD: // 'M'
                 dateFormatField = Field.MONTH;
-                appendMonth(buffer, count, formatData.months, formatData.shortMonths);
+                appendMonth(buffer, count, false);
                 break;
             case DATE_FIELD:
                 dateFormatField = Field.DAY_OF_MONTH;
                 field = Calendar.DATE;
                 break;
-            case HOUR_OF_DAY1_FIELD: // k
+            case HOUR_OF_DAY1_FIELD: // 'k'
                 dateFormatField = Field.HOUR_OF_DAY1;
                 int hour = calendar.get(Calendar.HOUR_OF_DAY);
                 appendNumber(buffer, count, hour == 0 ? 24 : hour);
                 break;
-            case HOUR_OF_DAY0_FIELD: // H
+            case HOUR_OF_DAY0_FIELD: // 'H'
                 dateFormatField = Field.HOUR_OF_DAY0;
                 field = Calendar.HOUR_OF_DAY;
                 break;
@@ -646,11 +629,11 @@
                 break;
             case STAND_ALONE_DAY_OF_WEEK_FIELD:
                 dateFormatField = Field.DAY_OF_WEEK;
-                appendDayOfWeek(buffer, count, formatData.longStandAloneWeekdays, formatData.shortStandAloneWeekdays);
+                appendDayOfWeek(buffer, count, true);
                 break;
             case DAY_OF_WEEK_FIELD:
                 dateFormatField = Field.DAY_OF_WEEK;
-                appendDayOfWeek(buffer, count, formatData.weekdays, formatData.shortWeekdays);
+                appendDayOfWeek(buffer, count, false);
                 break;
             case DAY_OF_YEAR_FIELD:
                 dateFormatField = Field.DAY_OF_YEAR;
@@ -672,22 +655,22 @@
                 dateFormatField = Field.AM_PM;
                 buffer.append(formatData.ampms[calendar.get(Calendar.AM_PM)]);
                 break;
-            case HOUR1_FIELD: // h
+            case HOUR1_FIELD: // 'h'
                 dateFormatField = Field.HOUR1;
                 hour = calendar.get(Calendar.HOUR);
                 appendNumber(buffer, count, hour == 0 ? 12 : hour);
                 break;
-            case HOUR0_FIELD: // K
+            case HOUR0_FIELD: // 'K'
                 dateFormatField = Field.HOUR0;
                 field = Calendar.HOUR;
                 break;
-            case TIMEZONE_FIELD: // z
+            case TIMEZONE_FIELD: // 'z'
                 dateFormatField = Field.TIME_ZONE;
                 appendTimeZone(buffer, count, true);
                 break;
-            case RFC_822_TIMEZONE_FIELD: // Z
+            case RFC_822_TIMEZONE_FIELD: // 'Z'
                 dateFormatField = Field.TIME_ZONE;
-                appendNumericTimeZone(buffer, false);
+                appendNumericTimeZone(buffer, count, false);
                 break;
         }
         if (field != -1) {
@@ -710,22 +693,38 @@
         }
     }
 
-    private void appendDayOfWeek(StringBuffer buffer, int count, String[] longs, String[] shorts) {
-        boolean isLong = (count > 3);
-        String[] days = isLong ? longs : shorts;
-        buffer.append(days[calendar.get(Calendar.DAY_OF_WEEK)]);
+    // See http://www.unicode.org/reports/tr35/#Date_Format_Patterns for the different counts.
+    private void appendDayOfWeek(StringBuffer buffer, int count, boolean standAlone) {
+      String[] days;
+      LocaleData ld = formatData.localeData;
+      if (count == 4) {
+        days = standAlone ? ld.longStandAloneWeekdayNames : formatData.weekdays;
+      } else if (count == 5) {
+        days = standAlone ? ld.tinyStandAloneWeekdayNames : formatData.localeData.tinyWeekdayNames;
+      } else {
+        days = standAlone ? ld.shortStandAloneWeekdayNames : formatData.shortWeekdays;
+      }
+      buffer.append(days[calendar.get(Calendar.DAY_OF_WEEK)]);
     }
 
-    private void appendMonth(StringBuffer buffer, int count, String[] longs, String[] shorts) {
-        int month = calendar.get(Calendar.MONTH);
-        if (count <= 2) {
-            appendNumber(buffer, count, month + 1);
-            return;
-        }
+    // See http://www.unicode.org/reports/tr35/#Date_Format_Patterns for the different counts.
+    private void appendMonth(StringBuffer buffer, int count, boolean standAlone) {
+      int month = calendar.get(Calendar.MONTH);
+      if (count <= 2) {
+        appendNumber(buffer, count, month + 1);
+        return;
+      }
 
-        boolean isLong = (count > 3);
-        String[] months = isLong ? longs : shorts;
-        buffer.append(months[month]);
+      String[] months;
+      LocaleData ld = formatData.localeData;
+      if (count == 4) {
+        months = standAlone ? ld.longStandAloneMonthNames : formatData.months;
+      } else if (count == 5) {
+        months = standAlone ? ld.tinyStandAloneMonthNames : ld.tinyMonthNames;
+      } else {
+        months = standAlone ? ld.shortStandAloneMonthNames : formatData.shortMonths;
+      }
+      buffer.append(months[month]);
     }
 
     /**
@@ -755,25 +754,24 @@
             }
         }
         // We didn't find what we were looking for, so default to a numeric time zone.
-        appendNumericTimeZone(buffer, generalTimeZone);
+        appendNumericTimeZone(buffer, count, generalTimeZone);
     }
 
-    /**
-     * @param generalTimeZone "GMT-08:00" rather than "-0800".
-     */
-    private void appendNumericTimeZone(StringBuffer buffer, boolean generalTimeZone) {
+    // See http://www.unicode.org/reports/tr35/#Date_Format_Patterns for the different counts.
+    // @param generalTimeZone "GMT-08:00" rather than "-0800".
+    private void appendNumericTimeZone(StringBuffer buffer, int count, boolean generalTimeZone) {
         int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
         char sign = '+';
         if (offset < 0) {
             sign = '-';
             offset = -offset;
         }
-        if (generalTimeZone) {
+        if (generalTimeZone || count == 4) {
             buffer.append("GMT");
         }
         buffer.append(sign);
         appendNumber(buffer, 2, offset / 3600000);
-        if (generalTimeZone) {
+        if (generalTimeZone || count >= 4) {
             buffer.append(':');
         }
         appendNumber(buffer, 2, (offset % 3600000) / 60000);
@@ -879,16 +877,14 @@
                     return position.getIndex();
                 }
                 break;
-            case STAND_ALONE_MONTH_FIELD: // L
-                return parseMonth(string, offset, count, absolute,
-                        formatData.longStandAloneMonths, formatData.shortStandAloneMonths);
-            case MONTH_FIELD: // M
-                return parseMonth(string, offset, count, absolute,
-                        formatData.months, formatData.shortMonths);
+            case STAND_ALONE_MONTH_FIELD: // 'L'
+                return parseMonth(string, offset, count, absolute, true);
+            case MONTH_FIELD: // 'M'
+                return parseMonth(string, offset, count, absolute, false);
             case DATE_FIELD:
                 field = Calendar.DATE;
                 break;
-            case HOUR_OF_DAY1_FIELD: // k
+            case HOUR_OF_DAY1_FIELD: // 'k'
                 ParsePosition position = new ParsePosition(offset);
                 Number result = parseNumber(absolute, string, position);
                 if (result == null) {
@@ -900,7 +896,7 @@
                 }
                 calendar.set(Calendar.HOUR_OF_DAY, hour);
                 return position.getIndex();
-            case HOUR_OF_DAY0_FIELD: // H
+            case HOUR_OF_DAY0_FIELD: // 'H'
                 field = Calendar.HOUR_OF_DAY;
                 break;
             case MINUTE_FIELD:
@@ -913,9 +909,9 @@
                 field = Calendar.MILLISECOND;
                 break;
             case STAND_ALONE_DAY_OF_WEEK_FIELD:
-                return parseDayOfWeek(string, offset, formatData.longStandAloneWeekdays, formatData.shortStandAloneWeekdays);
+                return parseDayOfWeek(string, offset, true);
             case DAY_OF_WEEK_FIELD:
-                return parseDayOfWeek(string, offset, formatData.weekdays, formatData.shortWeekdays);
+                return parseDayOfWeek(string, offset, false);
             case DAY_OF_YEAR_FIELD:
                 field = Calendar.DAY_OF_YEAR;
                 break;
@@ -930,7 +926,7 @@
                 break;
             case AM_PM_FIELD:
                 return parseText(string, offset, formatData.ampms, Calendar.AM_PM);
-            case HOUR1_FIELD: // h
+            case HOUR1_FIELD: // 'h'
                 position = new ParsePosition(offset);
                 result = parseNumber(absolute, string, position);
                 if (result == null) {
@@ -942,12 +938,12 @@
                 }
                 calendar.set(Calendar.HOUR, hour);
                 return position.getIndex();
-            case HOUR0_FIELD: // K
+            case HOUR0_FIELD: // 'K'
                 field = Calendar.HOUR;
                 break;
-            case TIMEZONE_FIELD: // z
+            case TIMEZONE_FIELD: // 'z'
                 return parseTimeZone(string, offset);
-            case RFC_822_TIMEZONE_FIELD: // Z
+            case RFC_822_TIMEZONE_FIELD: // 'Z'
                 return parseTimeZone(string, offset);
         }
         if (field != -1) {
@@ -956,23 +952,33 @@
         return offset;
     }
 
-    private int parseDayOfWeek(String string, int offset, String[] longs, String[] shorts) {
-        int index = parseText(string, offset, longs, Calendar.DAY_OF_WEEK);
-        if (index < 0) {
-            index = parseText(string, offset, shorts, Calendar.DAY_OF_WEEK);
-        }
-        return index;
+    private int parseDayOfWeek(String string, int offset, boolean standAlone) {
+      LocaleData ld = formatData.localeData;
+      int index = parseText(string, offset,
+                            standAlone ? ld.longStandAloneWeekdayNames : formatData.weekdays,
+                            Calendar.DAY_OF_WEEK);
+      if (index < 0) {
+        index = parseText(string, offset,
+                          standAlone ? ld.shortStandAloneWeekdayNames : formatData.shortWeekdays,
+                          Calendar.DAY_OF_WEEK);
+      }
+      return index;
     }
 
-    private int parseMonth(String string, int offset, int count, int absolute, String[] longs, String[] shorts) {
-        if (count <= 2) {
-            return parseNumber(absolute, string, offset, Calendar.MONTH, -1);
-        }
-        int index = parseText(string, offset, longs, Calendar.MONTH);
-        if (index < 0) {
-            index = parseText(string, offset, shorts, Calendar.MONTH);
-        }
-        return index;
+    private int parseMonth(String string, int offset, int count, int absolute, boolean standAlone) {
+      if (count <= 2) {
+        return parseNumber(absolute, string, offset, Calendar.MONTH, -1);
+      }
+      LocaleData ld = formatData.localeData;
+      int index = parseText(string, offset,
+                            standAlone ? ld.longStandAloneMonthNames : formatData.months,
+                            Calendar.MONTH);
+      if (index < 0) {
+        index = parseText(string, offset,
+                          standAlone ? ld.shortStandAloneMonthNames : formatData.shortMonths,
+                          Calendar.MONTH);
+      }
+      return index;
     }
 
     /**
diff --git a/luni/src/main/java/java/util/Formatter.java b/luni/src/main/java/java/util/Formatter.java
index 021da08..6ca8733 100644
--- a/luni/src/main/java/java/util/Formatter.java
+++ b/luni/src/main/java/java/util/Formatter.java
@@ -297,9 +297,9 @@
  * </tr>
  * </table>
  * <p>
- * It's also possible to format dates and times with {@code Formatter}, though you should seriously
- * consider using {@link java.text.SimpleDateFormat} via the factory methods in
- * {@link java.text.DateFormat} instead.
+ * It's also possible to format dates and times with {@code Formatter}, though you should
+ * use {@link java.text.SimpleDateFormat} (probably via the factory methods in
+ * {@link java.text.DateFormat}) instead.
  * The facilities offered by {@code Formatter} are low-level and place the burden of localization
  * on the developer. Using {@link java.text.DateFormat#getDateInstance},
  * {@link java.text.DateFormat#getTimeInstance}, and
@@ -310,11 +310,8 @@
  * which you can get with {@code "%tF"} (2010-01-22), {@code "%tF %tR"} (2010-01-22 13:39),
  * {@code "%tF %tT"} (2010-01-22 13:39:15), or {@code "%tF %tT%z"} (2010-01-22 13:39:15-0800).
  * <p>
- * As with the other conversions, date/time conversion has an uppercase format. Replacing
- * {@code %t} with {@code %T} will uppercase the field according to the rules of the formatter's
- * locale.
- * <p>
- * This table shows the date/time conversions:
+ * This table shows the date/time conversions, but you should use {@link java.text.SimpleDateFormat}
+ * instead:
  * <table BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
  * <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
  * <TD COLSPAN=4><B>Date/time conversions</B>
@@ -349,7 +346,7 @@
  * </tr>
  * <tr>
  * <td width="5%">{@code tc}</td>
- * <td width="25%">Locale-preferred date and time representation. (See {@link java.text.DateFormat} for more variations.)</td>
+ * <td width="25%">C library <i>asctime(3)</i>-like output. Do not use.</td>
  * <td width="30%">{@code format("%tc", cal);}</td>
  * <td width="30%">{@code Tue Apr 01 16:19:17 CEST 2008}</td>
  * </tr>
@@ -510,6 +507,10 @@
  * <td width="30%">{@code CEST}</td>
  * </tr>
  * </table>
+ * <p>
+ * As with the other conversions, date/time conversion has an uppercase format. Replacing
+ * {@code %t} with {@code %T} will uppercase the field according to the rules of the formatter's
+ * locale.
  * <p><i>Number localization</i>. Some conversions use localized decimal digits rather than the
  * usual ASCII digits. So formatting {@code 123} with {@code %d} will give 123 in English locales
  * but &#x0661;&#x0662;&#x0663; in appropriate Arabic locales, for example. This number localization
diff --git a/luni/src/test/java/libcore/java/security/SignatureTest.java b/luni/src/test/java/libcore/java/security/SignatureTest.java
index ac8b172..4e2cf61 100644
--- a/luni/src/test/java/libcore/java/security/SignatureTest.java
+++ b/luni/src/test/java/libcore/java/security/SignatureTest.java
@@ -138,7 +138,7 @@
 
         /* ENGINE-based private key */
         NativeCryptoTest.loadTestEngine();
-        OpenSSLEngine engine = OpenSSLEngine.getInstance("test");
+        OpenSSLEngine engine = OpenSSLEngine.getInstance(NativeCryptoTest.TEST_ENGINE_ID);
         PrivateKey privKey = engine.getPrivateKeyById(pem_private);
         assertTrue(privKey instanceof RSAPrivateKey);
 
diff --git a/luni/src/test/java/libcore/java/text/OldSimpleDateFormatTest.java b/luni/src/test/java/libcore/java/text/OldSimpleDateFormatTest.java
index ff24bb6..1cc7554 100644
--- a/luni/src/test/java/libcore/java/text/OldSimpleDateFormatTest.java
+++ b/luni/src/test/java/libcore/java/text/OldSimpleDateFormatTest.java
@@ -245,7 +245,7 @@
         test.test(" MM", cal, " 06", DateFormat.MONTH_FIELD);
         test.test(" MMM", cal, " Jun", DateFormat.MONTH_FIELD);
         test.test(" MMMM", cal, " June", DateFormat.MONTH_FIELD);
-        test.test(" MMMMM", cal, " June", DateFormat.MONTH_FIELD);
+        test.test(" MMMMM", cal, " J", DateFormat.MONTH_FIELD);
 
         test.test(" d", cal, " 2", DateFormat.DATE_FIELD);
         test.test(" d", new GregorianCalendar(1999, Calendar.NOVEMBER, 12),
@@ -295,7 +295,7 @@
         test.test(" EE", cal, " Wed", DateFormat.DAY_OF_WEEK_FIELD);
         test.test(" EEE", cal, " Wed", DateFormat.DAY_OF_WEEK_FIELD);
         test.test(" EEEE", cal, " Wednesday", DateFormat.DAY_OF_WEEK_FIELD);
-        test.test(" EEEEE", cal, " Wednesday", DateFormat.DAY_OF_WEEK_FIELD);
+        test.test(" EEEEE", cal, " W", DateFormat.DAY_OF_WEEK_FIELD);
 
         test.test(" D", cal, " 153", DateFormat.DAY_OF_YEAR_FIELD);
         test.test(" DD", cal, " 153", DateFormat.DAY_OF_YEAR_FIELD);
@@ -405,7 +405,8 @@
 
         format.setTimeZone(tz0001);
         test.test(" Z", cal, " +0001", DateFormat.TIMEZONE_FIELD);
-        test.test(" ZZZZ", cal, " +0001", DateFormat.TIMEZONE_FIELD);
+        test.test(" ZZZZ", cal, " GMT+00:01", DateFormat.TIMEZONE_FIELD);
+        test.test(" ZZZZZ", cal, " +00:01", DateFormat.TIMEZONE_FIELD);
         format.setTimeZone(tz0130);
         test.test(" Z", cal, " +0130", DateFormat.TIMEZONE_FIELD);
         format.setTimeZone(tzMinus0130);
@@ -441,22 +442,18 @@
         Date winterDate = new GregorianCalendar(1999, Calendar.JANUARY, 12).getTime();
 
         FormatTester test = new FormatTester();
-        test.verifyFormatTimezone("GMT-7", "GMT-07:00, GMT-07:00", "-0700, -0700", summerDate);
-        test.verifyFormatTimezone("GMT-7", "GMT-07:00, GMT-07:00", "-0700, -0700", winterDate);
+        test.verifyFormatTimezone("GMT-7", "GMT-07:00, GMT-07:00", "-0700, GMT-07:00", summerDate);
+        test.verifyFormatTimezone("GMT-7", "GMT-07:00, GMT-07:00", "-0700, GMT-07:00", winterDate);
 
-        test.verifyFormatTimezone("GMT+14", "GMT+14:00, GMT+14:00", "+1400, +1400", summerDate);
-        test.verifyFormatTimezone("GMT+14", "GMT+14:00, GMT+14:00", "+1400, +1400", winterDate);
+        test.verifyFormatTimezone("GMT+14", "GMT+14:00, GMT+14:00", "+1400, GMT+14:00", summerDate);
+        test.verifyFormatTimezone("GMT+14", "GMT+14:00, GMT+14:00", "+1400, GMT+14:00", winterDate);
 
-        test.verifyFormatTimezone("America/Los_Angeles", "PDT, Pacific Daylight Time",
-                "-0700, -0700", summerDate);
-        test.verifyFormatTimezone("America/Los_Angeles", "PST, Pacific Standard Time",
-                "-0800, -0800", winterDate);
+        test.verifyFormatTimezone("America/Los_Angeles", "PDT, Pacific Daylight Time", "-0700, GMT-07:00", summerDate);
+        test.verifyFormatTimezone("America/Los_Angeles", "PST, Pacific Standard Time", "-0800, GMT-08:00", winterDate);
 
         // this fails on the RI!
-        test.verifyFormatTimezone("America/Detroit", "EDT, Eastern Daylight Time",
-                "-0400, -0400", summerDate);
-        test.verifyFormatTimezone("America/Detroit", "EST, Eastern Standard Time",
-                "-0500, -0500", winterDate);
+        test.verifyFormatTimezone("America/Detroit", "EDT, Eastern Daylight Time", "-0400, GMT-04:00", summerDate);
+        test.verifyFormatTimezone("America/Detroit", "EST, Eastern Standard Time", "-0500, GMT-05:00", winterDate);
 
         assertFalse(test.testsFailed);
     }
diff --git a/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java b/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
index cd54d1e..21d7302 100644
--- a/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
+++ b/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
@@ -77,6 +77,104 @@
         assertEquals(Calendar.TUESDAY, parseDate(ru, "cccc", "\u0412\u0442\u043e\u0440\u043d\u0438\u043a").get(Calendar.DAY_OF_WEEK));
     }
 
+    // The RI fails this test because it doesn't fully support UTS #35.
+    // https://code.google.com/p/android/issues/detail?id=39616
+    public void testFiveCount_parsing() throws Exception {
+      // It's pretty silly to try to parse the shortest names, because they're almost always ambiguous.
+      try {
+        parseDate(Locale.ENGLISH, "MMMMM", "J");
+        fail();
+      } catch (junit.framework.AssertionFailedError expected) {
+      }
+      try {
+        parseDate(Locale.ENGLISH, "LLLLL", "J");
+        fail();
+      } catch (junit.framework.AssertionFailedError expected) {
+      }
+      try {
+        parseDate(Locale.ENGLISH, "EEEEE", "T");
+        fail();
+      } catch (junit.framework.AssertionFailedError expected) {
+      }
+      try {
+        parseDate(Locale.ENGLISH, "ccccc", "T");
+        fail();
+      } catch (junit.framework.AssertionFailedError expected) {
+      }
+    }
+
+    // The RI fails this test because it doesn't fully support UTS #35.
+    // https://code.google.com/p/android/issues/detail?id=39616
+    public void testFiveCount_M() throws Exception {
+      TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
+      assertEquals("1", formatDate(Locale.ENGLISH, "M"));
+      assertEquals("01", formatDate(Locale.ENGLISH, "MM"));
+      assertEquals("Jan", formatDate(Locale.ENGLISH, "MMM"));
+      assertEquals("January", formatDate(Locale.ENGLISH, "MMMM"));
+      assertEquals("J", formatDate(Locale.ENGLISH, "MMMMM"));
+    }
+
+    // The RI fails this test because it doesn't fully support UTS #35.
+    // https://code.google.com/p/android/issues/detail?id=39616
+    public void testFiveCount_L() throws Exception {
+      TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
+      assertEquals("1", formatDate(Locale.ENGLISH, "L"));
+      assertEquals("01", formatDate(Locale.ENGLISH, "LL"));
+      assertEquals("Jan", formatDate(Locale.ENGLISH, "LLL"));
+      assertEquals("January", formatDate(Locale.ENGLISH, "LLLL"));
+      assertEquals("J", formatDate(Locale.ENGLISH, "LLLLL"));
+    }
+
+    // The RI fails this test because it doesn't fully support UTS #35.
+    // https://code.google.com/p/android/issues/detail?id=39616
+    public void testFiveCount_E() throws Exception {
+      TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
+      assertEquals("Thu", formatDate(Locale.ENGLISH, "E"));
+      assertEquals("Thu", formatDate(Locale.ENGLISH, "EE"));
+      assertEquals("Thu", formatDate(Locale.ENGLISH, "EEE"));
+      assertEquals("Thursday", formatDate(Locale.ENGLISH, "EEEE"));
+      assertEquals("T", formatDate(Locale.ENGLISH, "EEEEE"));
+      // assertEquals("Th", formatDate(Locale.ENGLISH, "EEEEEE")); // icu4c doesn't support 6.
+    }
+
+    // The RI fails this test because it doesn't fully support UTS #35.
+    // https://code.google.com/p/android/issues/detail?id=39616
+    public void testFiveCount_c() throws Exception {
+      TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
+      assertEquals("Thu", formatDate(Locale.ENGLISH, "c"));
+      assertEquals("Thu", formatDate(Locale.ENGLISH, "cc"));
+      assertEquals("Thu", formatDate(Locale.ENGLISH, "ccc"));
+      assertEquals("Thursday", formatDate(Locale.ENGLISH, "cccc"));
+      assertEquals("T", formatDate(Locale.ENGLISH, "ccccc"));
+      // assertEquals("Th", formatDate(Locale.ENGLISH, "cccccc")); // icu4c doesn't support 6.
+    }
+
+    // The RI fails this test because it doesn't fully support UTS #35.
+    // https://code.google.com/p/android/issues/detail?id=39616
+    public void testFiveCount_Z() throws Exception {
+      TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
+      assertEquals("+0000", formatDate(Locale.ENGLISH, "Z"));
+      assertEquals("+0000", formatDate(Locale.ENGLISH, "ZZ"));
+      assertEquals("+0000", formatDate(Locale.ENGLISH, "ZZZ"));
+      assertEquals("GMT+00:00", formatDate(Locale.ENGLISH, "ZZZZ"));
+      assertEquals("+00:00", formatDate(Locale.ENGLISH, "ZZZZZ"));
+    }
+
+    // The RI fails this test because it doesn't fully support UTS #35.
+    // https://code.google.com/p/android/issues/detail?id=39616
+    public void test_parsing_Z() throws Exception {
+      TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
+      assertEquals(1325421240000L, parseTime("yyyy-MM-dd' 'Z", "2012-01-01 -1234"));
+      assertEquals(1325421240000L, parseTime("yyyy-MM-dd' 'ZZ", "2012-01-01 -1234"));
+      assertEquals(1325421240000L, parseTime("yyyy-MM-dd' 'ZZZ", "2012-01-01 -1234"));
+      assertEquals(1325421240000L, parseTime("yyyy-MM-dd' 'ZZZZ", "2012-01-01 GMT-12:34"));
+      assertEquals(1325421240000L, parseTime("yyyy-MM-dd' 'ZZZZZ", "2012-01-01 -12:34"));
+    }
+
+    private static long parseTime(String fmt, String value) {
+      return parseDate(Locale.ENGLISH, fmt, value).getTime().getTime();
+    }
+
     public void test2038() {
         SimpleDateFormat format = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy", Locale.US);
         format.setTimeZone(TimeZone.getTimeZone("UTC"));
@@ -92,13 +190,14 @@
         assertEquals("Sun Feb 07 06:28:16 2106",
                 format.format(new Date((2L + Integer.MAX_VALUE + Integer.MAX_VALUE) * 1000L)));
     }
+
     private String formatDate(Locale l, String fmt) {
         DateFormat dateFormat = new SimpleDateFormat(fmt, l);
         dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
         return dateFormat.format(new Date(0));
     }
 
-    private Calendar parseDate(Locale l, String fmt, String value) {
+    private static Calendar parseDate(Locale l, String fmt, String value) {
         SimpleDateFormat sdf = new SimpleDateFormat(fmt, l);
         ParsePosition pp = new ParsePosition(0);
         Date d = sdf.parse(value, pp);
diff --git a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java
index 47ab6cc..d65dd4b 100644
--- a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java
+++ b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/MacTest.java
@@ -897,7 +897,7 @@
 
         Provider p = Security.getProvider(OpenSSLProvider.PROVIDER_NAME);
         NativeCryptoTest.loadTestEngine();
-        OpenSSLEngine engine = OpenSSLEngine.getInstance("test");
+        OpenSSLEngine engine = OpenSSLEngine.getInstance(NativeCryptoTest.TEST_ENGINE_ID);
 
         /*
          * The "-HMAC-" prefix is a special prefix recognized by
diff --git a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java
index 41ced3e..d531596 100644
--- a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java
+++ b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java
@@ -56,7 +56,7 @@
 
 public class NativeCryptoTest extends TestCase {
     /** Corresponds to the native test library "libjavacoretests.so" */
-    private static final String NATIVE_LIBRARY_NAME = "javacoretests";
+    public static final String TEST_ENGINE_ID = "javacoretests";
 
     private static final int NULL = 0;
     private static final FileDescriptor INVALID_FD = new FileDescriptor();
@@ -2007,7 +2007,7 @@
      * immediately.
      */
     public static void loadTestEngine() throws Exception {
-        int testEngine = NativeCrypto.ENGINE_by_id("test");
+        int testEngine = NativeCrypto.ENGINE_by_id(TEST_ENGINE_ID);
         if (testEngine != 0) {
             NativeCrypto.ENGINE_finish(testEngine);
             return;
@@ -2035,14 +2035,14 @@
             assertEquals(1, NativeCrypto.ENGINE_ctrl_cmd_string(dynEngine, "LIST_ADD", "2", 0));
 
             // Do a direct load of the ENGINE.
-            assertEquals(1, NativeCrypto.ENGINE_ctrl_cmd_string(dynEngine, "SO_PATH",
-                    NATIVE_LIBRARY_NAME, 0));
+            assertEquals(1,
+                    NativeCrypto.ENGINE_ctrl_cmd_string(dynEngine, "ID", TEST_ENGINE_ID, 0));
             assertEquals(1, NativeCrypto.ENGINE_ctrl_cmd_string(dynEngine, "LOAD", null, 0));
         } finally {
             NativeCrypto.ENGINE_finish(dynEngine);
         }
 
-        testEngine = NativeCrypto.ENGINE_by_id("test");
+        testEngine = NativeCrypto.ENGINE_by_id(TEST_ENGINE_ID);
         if (testEngine == 0) {
             fail("could not load test engine");
         }
@@ -2052,7 +2052,7 @@
     public void test_ENGINE_by_id_TestEngine() throws Exception {
         loadTestEngine();
 
-        int engine = NativeCrypto.ENGINE_by_id("test");
+        int engine = NativeCrypto.ENGINE_by_id(TEST_ENGINE_ID);
         assertTrue(engine != 0);
         NativeCrypto.ENGINE_add(engine);
 
diff --git a/luni/src/test/native/test_openssl_engine.cpp b/luni/src/test/native/test_openssl_engine.cpp
index 787f29e..9a0f3b3 100644
--- a/luni/src/test/native/test_openssl_engine.cpp
+++ b/luni/src/test/native/test_openssl_engine.cpp
@@ -26,7 +26,7 @@
 #include <openssl/pem.h>
 
 #define DYNAMIC_ENGINE
-#define TEST_ENGINE_ID   "test"
+#define TEST_ENGINE_ID   "javacoretests"
 #define TEST_ENGINE_NAME "libcore test engine"
 
 struct RSA_Delete {