]> gitweb.fperrin.net Git - Dictionary.git/blobdiff - jars/icu4j-52_1/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java
Upgrade ICU4J.
[Dictionary.git] / jars / icu4j-52_1 / main / classes / core / src / com / ibm / icu / text / SimpleDateFormat.java
similarity index 63%
rename from jars/icu4j-4_8_1_1/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java
rename to jars/icu4j-52_1/main/classes/core/src/com/ibm/icu/text/SimpleDateFormat.java
index e64aaedf0bea3583891f2f5e725c1ccddcc1d39d..283d33ed49780c57320db438af761a4cb84a9349 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *******************************************************************************
- * Copyright (C) 1996-2011, International Business Machines Corporation and    *
+ * Copyright (C) 1996-2013, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -59,65 +59,549 @@ import com.ibm.icu.util.ULocale.Category;
  * For more information on using these methods, see
  * {@link DateFormat}.
  *
- * <p>
- * <strong>Time Format Syntax:</strong>
- * <p>
- * To specify the time format use a <em>time pattern</em> string.
- * In this pattern, all ASCII letters are reserved as pattern letters,
- * which are defined as the following:
+ * <p><strong>Date and Time Patterns:</strong></p>
+ *
+ * <p>Date and time formats are specified by <em>date and time pattern</em> strings.
+ * Within date and time pattern strings, all unquoted ASCII letters [A-Za-z] are reserved
+ * as pattern letters representing calendar fields. <code>SimpleDateFormat</code> supports
+ * the date and time formatting algorithm and pattern letters defined by <a href="http://www.unicode.org/reports/tr35/">UTS#35
+ * Unicode Locale Data Markup Language (LDML)</a>. The following pattern letters are
+ * currently available:</p>
  * <blockquote>
- * <pre>
- * Symbol   Meaning                 Presentation        Example
- * ------   -------                 ------------        -------
- * G        era designator          (Text)              AD
- * y&#x2020;       year                    (Number)            1996
- * Y*       year (week of year)     (Number)            1997
- * u*       extended year           (Number)            4601
- * M        month in year           (Text & Number)     July & 07
- * d        day in month            (Number)            10
- * h        hour in am/pm (1~12)    (Number)            12
- * H        hour in day (0~23)      (Number)            0
- * m        minute in hour          (Number)            30
- * s        second in minute        (Number)            55
- * S        fractional second       (Number)            978
- * E        day of week             (Text)              Tuesday
- * e*       day of week (local 1~7) (Text & Number)     Tuesday & 2
- * D        day in year             (Number)            189
- * F        day of week in month    (Number)            2 (2nd Wed in July)
- * w        week in year            (Number)            27
- * W        week in month           (Number)            2
- * a        am/pm marker            (Text)              PM
- * k        hour in day (1~24)      (Number)            24
- * K        hour in am/pm (0~11)    (Number)            0
- * z        time zone               (Text)              Pacific Standard Time
- * Z        time zone (RFC 822)     (Number)            -0800
- * v        time zone (generic)     (Text)              Pacific Time
- * V        time zone (location)    (Text)              United States (Los Angeles)
- * g*       Julian day              (Number)            2451334
- * A*       milliseconds in day     (Number)            69540000
- * Q*       quarter in year         (Text & Number)     Q1 & 01
- * c*       stand alone day of week (Text & Number)     Tuesday & 2
- * L*       stand alone month       (Text & Number)     July & 07
- * q*       stand alone quarter     (Text & Number)     Q1 & 01
- * '        escape for text         (Delimiter)         'Date='
- * ''       single quote            (Literal)           'o''clock'
- * </pre>
+ * <table border="1">
+ *     <tr>
+ *         <th>Field</th>
+ *         <th style="text-align: center">Sym.</th>
+ *         <th style="text-align: center">No.</th>
+ *         <th>Example</th>
+ *         <th>Description</th>
+ *     </tr>
+ *     <tr>
+ *         <th rowspan="3">era</th>
+ *         <td style="text-align: center" rowspan="3">G</td>
+ *         <td style="text-align: center">1..3</td>
+ *         <td>AD</td>
+ *         <td rowspan="3">Era - Replaced with the Era string for the current date. One to three letters for the 
+ *         abbreviated form, four letters for the long form, five for the narrow form.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">4</td>
+ *         <td>Anno Domini</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">5</td>
+ *         <td>A</td>
+ *     </tr>
+ *     <tr>
+ *         <th rowspan="6">year</th>
+ *         <td style="text-align: center">y</td>
+ *         <td style="text-align: center">1..n</td>
+ *         <td>1996</td>
+ *         <td>Year. Normally the length specifies the padding, but for two letters it also specifies the maximum
+ *         length. Example:<div align="center">
+ *             <center>
+ *             <table border="1" cellpadding="2" cellspacing="0">
+ *                 <tr>
+ *                     <th>Year</th>
+ *                     <th style="text-align: right">y</th>
+ *                     <th style="text-align: right">yy</th>
+ *                     <th style="text-align: right">yyy</th>
+ *                     <th style="text-align: right">yyyy</th>
+ *                     <th style="text-align: right">yyyyy</th>
+ *                 </tr>
+ *                 <tr>
+ *                     <td>AD 1</td>
+ *                     <td style="text-align: right">1</td>
+ *                     <td style="text-align: right">01</td>
+ *                     <td style="text-align: right">001</td>
+ *                     <td style="text-align: right">0001</td>
+ *                     <td style="text-align: right">00001</td>
+ *                 </tr>
+ *                 <tr>
+ *                     <td>AD 12</td>
+ *                     <td style="text-align: right">12</td>
+ *                     <td style="text-align: right">12</td>
+ *                     <td style="text-align: right">012</td>
+ *                     <td style="text-align: right">0012</td>
+ *                     <td style="text-align: right">00012</td>
+ *                 </tr>
+ *                 <tr>
+ *                     <td>AD 123</td>
+ *                     <td style="text-align: right">123</td>
+ *                     <td style="text-align: right">23</td>
+ *                     <td style="text-align: right">123</td>
+ *                     <td style="text-align: right">0123</td>
+ *                     <td style="text-align: right">00123</td>
+ *                 </tr>
+ *                 <tr>
+ *                     <td>AD 1234</td>
+ *                     <td style="text-align: right">1234</td>
+ *                     <td style="text-align: right">34</td>
+ *                     <td style="text-align: right">1234</td>
+ *                     <td style="text-align: right">1234</td>
+ *                     <td style="text-align: right">01234</td>
+ *                 </tr>
+ *                 <tr>
+ *                     <td>AD 12345</td>
+ *                     <td style="text-align: right">12345</td>
+ *                     <td style="text-align: right">45</td>
+ *                     <td style="text-align: right">12345</td>
+ *                     <td style="text-align: right">12345</td>
+ *                     <td style="text-align: right">12345</td>
+ *                 </tr>
+ *             </table>
+ *             </center></div>
+ *         </td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">Y</td>
+ *         <td style="text-align: center">1..n</td>
+ *         <td>1997</td>
+ *         <td>Year (in "Week of Year" based calendars). Normally the length specifies the padding,
+ *         but for two letters it also specifies the maximum length. This year designation is used in ISO
+ *         year-week calendar as defined by ISO 8601, but can be used in non-Gregorian based calendar systems
+ *         where week date processing is desired. May not always be the same value as calendar year.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">u</td>
+ *         <td style="text-align: center">1..n</td>
+ *         <td>4601</td>
+ *         <td>Extended year. This is a single number designating the year of this calendar system, encompassing
+ *         all supra-year fields. For example, for the Julian calendar system, year numbers are positive, with an
+ *         era of BCE or CE. An extended year value for the Julian calendar system assigns positive values to CE
+ *         years and negative values to BCE years, with 1 BCE being year 0.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center" rowspan="3">U</td>
+ *         <td style="text-align: center">1..3</td>
+ *         <td>甲子</td>
+ *         <td rowspan="3">Cyclic year name. Calendars such as the Chinese lunar calendar (and related calendars)
+ *         and the Hindu calendars use 60-year cycles of year names. Use one through three letters for the abbreviated
+ *         name, four for the full name, or five for the narrow name (currently the data only provides abbreviated names,
+ *         which will be used for all requested name widths). If the calendar does not provide cyclic year name data,
+ *         or if the year value to be formatted is out of the range of years for which cyclic name data is provided,
+ *         then numeric formatting is used (behaves like 'y').</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">4</td>
+ *         <td>(currently also 甲子)</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">5</td>
+ *         <td>(currently also 甲子)</td>
+ *     </tr>
+ *     <tr>
+ *         <th rowspan="6">quarter</th>
+ *         <td rowspan="3" style="text-align: center">Q</td>
+ *         <td style="text-align: center">1..2</td>
+ *         <td>02</td>
+ *         <td rowspan="3">Quarter - Use one or two for the numerical quarter, three for the abbreviation, or four 
+ *         for the full name.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">3</td>
+ *         <td>Q2</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">4</td>
+ *         <td>2nd quarter</td>
+ *     </tr>
+ *     <tr>
+ *         <td rowspan="3" style="text-align: center">q</td>
+ *         <td style="text-align: center">1..2</td>
+ *         <td>02</td>
+ *         <td rowspan="3"><b>Stand-Alone</b> Quarter - Use one or two for the numerical quarter, three for the abbreviation, 
+ *         or four for the full name.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">3</td>
+ *         <td>Q2</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">4</td>
+ *         <td>2nd quarter</td>
+ *     </tr>
+ *     <tr>
+ *         <th rowspan="8">month</th>
+ *         <td rowspan="4" style="text-align: center">M</td>
+ *         <td style="text-align: center">1..2</td>
+ *         <td>09</td>
+ *         <td rowspan="4">Month - Use one or two for the numerical month, three for the abbreviation, four for
+ *         the full name, or five for the narrow name.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">3</td>
+ *         <td>Sept</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">4</td>
+ *         <td>September</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">5</td>
+ *         <td>S</td>
+ *     </tr>
+ *     <tr>
+ *         <td rowspan="4" style="text-align: center">L</td>
+ *         <td style="text-align: center">1..2</td>
+ *         <td>09</td>
+ *         <td rowspan="4"><b>Stand-Alone</b> Month - Use one or two for the numerical month, three for the abbreviation, 
+ *         or four for the full name, or 5 for the narrow name.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">3</td>
+ *         <td>Sept</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">4</td>
+ *         <td>September</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">5</td>
+ *         <td>S</td>
+ *     </tr>
+ *     <tr>
+ *         <th rowspan="2">week</th>
+ *         <td style="text-align: center">w</td>
+ *         <td style="text-align: center">1..2</td>
+ *         <td>27</td>
+ *         <td>Week of Year.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">W</td>
+ *         <td style="text-align: center">1</td>
+ *         <td>3</td>
+ *         <td>Week of Month</td>
+ *     </tr>
+ *     <tr>
+ *         <th rowspan="4">day</th>
+ *         <td style="text-align: center">d</td>
+ *         <td style="text-align: center">1..2</td>
+ *         <td>1</td>
+ *         <td>Date - Day of the month</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">D</td>
+ *         <td style="text-align: center">1..3</td>
+ *         <td>345</td>
+ *         <td>Day of year</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">F</td>
+ *         <td style="text-align: center">1</td>
+ *         <td>2</td>
+ *         <td>Day of Week in Month. The example is for the 2nd Wed in July</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">g</td>
+ *         <td style="text-align: center">1..n</td>
+ *         <td>2451334</td>
+ *         <td>Modified Julian day. This is different from the conventional Julian day number in two regards.
+ *         First, it demarcates days at local zone midnight, rather than noon GMT. Second, it is a local number;
+ *         that is, it depends on the local time zone. It can be thought of as a single number that encompasses 
+ *         all the date-related fields.</td>
+ *     </tr>
+ *     <tr>
+ *         <th rowspan="14">week<br>
+ *         day</th>
+ *         <td rowspan="4" style="text-align: center">E</td>
+ *         <td style="text-align: center">1..3</td>
+ *         <td>Tues</td>
+ *         <td rowspan="4">Day of week - Use one through three letters for the short day, or four for the full name, 
+ *         five for the narrow name, or six for the short name.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">4</td>
+ *         <td>Tuesday</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">5</td>
+ *         <td>T</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">6</td>
+ *         <td>Tu</td>
+ *     </tr>
+ *     <tr>
+ *         <td rowspan="5" style="text-align: center">e</td>
+ *         <td style="text-align: center">1..2</td>
+ *         <td>2</td>
+ *         <td rowspan="5">Local day of week. Same as E except adds a numeric value that will depend on the local
+ *         starting day of the week, using one or two letters. For this example, Monday is the first day of the week.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">3</td>
+ *         <td>Tues</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">4</td>
+ *         <td>Tuesday</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">5</td>
+ *         <td>T</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">6</td>
+ *         <td>Tu</td>
+ *     </tr>
+ *     <tr>
+ *         <td rowspan="5" style="text-align: center">c</td>
+ *         <td style="text-align: center">1</td>
+ *         <td>2</td>
+ *         <td rowspan="5"><b>Stand-Alone</b> local day of week - Use one letter for the local numeric value (same
+ *         as 'e'), three for the short day, four for the full name, five for the narrow name, or six for
+ *         the short name.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">3</td>
+ *         <td>Tues</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">4</td>
+ *         <td>Tuesday</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">5</td>
+ *         <td>T</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">6</td>
+ *         <td>Tu</td>
+ *     </tr>
+ *     <tr>
+ *         <th>period</th>
+ *         <td style="text-align: center">a</td>
+ *         <td style="text-align: center">1</td>
+ *         <td>AM</td>
+ *         <td>AM or PM</td>
+ *     </tr>
+ *     <tr>
+ *         <th rowspan="4">hour</th>
+ *         <td style="text-align: center">h</td>
+ *         <td style="text-align: center">1..2</td>
+ *         <td>11</td>
+ *         <td>Hour [1-12]. When used in skeleton data or in a skeleton passed in an API for flexible data pattern
+ *         generation, it should match the 12-hour-cycle format preferred by the locale (h or K); it should not match
+ *         a 24-hour-cycle format (H or k). Use hh for zero padding.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">H</td>
+ *         <td style="text-align: center">1..2</td>
+ *         <td>13</td>
+ *         <td>Hour [0-23]. When used in skeleton data or in a skeleton passed in an API for flexible data pattern
+ *         generation, it should match the 24-hour-cycle format preferred by the locale (H or k); it should not match a
+ *         12-hour-cycle format (h or K). Use HH for zero padding.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">K</td>
+ *         <td style="text-align: center">1..2</td>
+ *         <td>0</td>
+ *         <td>Hour [0-11]. When used in a skeleton, only matches K or h, see above. Use KK for zero padding.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">k</td>
+ *         <td style="text-align: center">1..2</td>
+ *         <td>24</td>
+ *         <td>Hour [1-24]. When used in a skeleton, only matches k or H, see above. Use kk for zero padding.</td>
+ *     </tr>
+ *     <tr>
+ *         <th>minute</th>
+ *         <td style="text-align: center">m</td>
+ *         <td style="text-align: center">1..2</td>
+ *         <td>59</td>
+ *         <td>Minute. Use one or two for zero padding.</td>
+ *     </tr>
+ *     <tr>
+ *         <th rowspan="3">second</th>
+ *         <td style="text-align: center">s</td>
+ *         <td style="text-align: center">1..2</td>
+ *         <td>12</td>
+ *         <td>Second. Use one or two for zero padding.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">S</td>
+ *         <td style="text-align: center">1..n</td>
+ *         <td>3456</td>
+ *         <td>Fractional Second - truncates (like other time fields) to the count of letters.
+ *         (example shows display using pattern SSSS for seconds value 12.34567)</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">A</td>
+ *         <td style="text-align: center">1..n</td>
+ *         <td>69540000</td>
+ *         <td>Milliseconds in day. This field behaves <i>exactly</i> like a composite of all time-related fields,
+ *         not including the zone fields. As such, it also reflects discontinuities of those fields on DST transition
+ *         days. On a day of DST onset, it will jump forward. On a day of DST cessation, it will jump backward. This
+ *         reflects the fact that is must be combined with the offset field to obtain a unique local time value.</td>
+ *     </tr>
+ *     <tr>
+ *         <th rowspan="23">zone</th>
+ *         <td rowspan="2" style="text-align: center">z</td>
+ *         <td style="text-align: center">1..3</td>
+ *         <td>PDT</td>
+ *         <td>The <i>short specific non-location format</i>.
+ *         Where that is unavailable, falls back to the <i>short localized GMT format</i> ("O").</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">4</td>
+ *         <td>Pacific Daylight Time</td>
+ *         <td>The <i>long specific non-location format</i>.
+ *         Where that is unavailable, falls back to the <i>long localized GMT format</i> ("OOOO").</td>
+ *     </tr>
+ *     <tr>
+ *         <td rowspan="3" style="text-align: center">Z</td>
+ *         <td style="text-align: center">1..3</td>
+ *         <td>-0800</td>
+ *         <td>The <i>ISO8601 basic format</i> with hours, minutes and optional seconds fields.
+ *         The format is equivalent to RFC 822 zone format (when optional seconds field is absent).
+ *         This is equivalent to the "xxxx" specifier.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">4</td>
+ *         <td>GMT-8:00</td>
+ *         <td>The <i>long localized GMT format</i>.
+ *         This is equivalent to the "OOOO" specifier.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">5</td>
+ *         <td>-08:00<br>
+ *         -07:52:58</td>
+ *         <td>The <i>ISO8601 extended format</i> with hours, minutes and optional seconds fields.
+ *         The ISO8601 UTC indicator "Z" is used when local time offset is 0.
+ *         This is equivalent to the "XXXXX" specifier.</td>
+ *     </tr>
+ *     <tr>
+ *         <td rowspan="2" style="text-align: center">O</td>
+ *         <td style="text-align: center">1</td>
+ *         <td>GMT-8</td>
+ *         <td>The <i>short localized GMT format</i>.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">4</td>
+ *         <td>GMT-08:00</td>
+ *         <td>The <i>long localized GMT format</i>.</td>
+ *     </tr>
+ *     <tr>
+ *         <td rowspan="2" style="text-align: center">v</td>
+ *         <td style="text-align: center">1</td>
+ *         <td>PT</td>
+ *         <td>The <i>short generic non-location format</i>.
+ *         Where that is unavailable, falls back to the <i>generic location format</i> ("VVVV"),
+ *         then the <i>short localized GMT format</i> as the final fallback.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">4</td>
+ *         <td>Pacific Time</td>
+ *         <td>The <i>long generic non-location format</i>.
+ *         Where that is unavailable, falls back to <i>generic location format</i> ("VVVV").
+ *     </tr>
+ *     <tr>
+ *         <td rowspan="4" style="text-align: center">V</td>
+ *         <td style="text-align: center">1</td>
+ *         <td>uslax</td>
+ *         <td>The short time zone ID.
+ *         Where that is unavailable, the special short time zone ID <i>unk</i> (Unknown Zone) is used.<br>
+ *         <i><b>Note</b>: This specifier was originally used for a variant of the short specific non-location format,
+ *         but it was deprecated in the later version of the LDML specification. In CLDR 23/ICU 51, the definition of
+ *         the specifier was changed to designate a short time zone ID.</i></td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">2</td>
+ *         <td>America/Los_Angeles</td>
+ *         <td>The long time zone ID.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">3</td>
+ *         <td>Los Angeles</td>
+ *         <td>The exemplar city (location) for the time zone.
+ *         Where that is unavailable, the localized exemplar city name for the special zone <i>Etc/Unknown</i> is used
+ *         as the fallback (for example, "Unknown City"). </td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">4</td>
+ *         <td>Los Angeles Time</td>
+ *         <td>The <i>generic location format</i>.
+ *         Where that is unavailable, falls back to the <i>long localized GMT format</i> ("OOOO";
+ *         Note: Fallback is only necessary with a GMT-style Time Zone ID, like Etc/GMT-830.)<br>
+ *         This is especially useful when presenting possible timezone choices for user selection, 
+ *         since the naming is more uniform than the "v" format.</td>
+ *     </tr>
+ *     <tr>
+ *         <td rowspan="5" style="text-align: center">X</td>
+ *         <td style="text-align: center">1</td>
+ *         <td>-08<br>
+ *         +0530<br>
+ *         Z</td>
+ *         <td>The <i>ISO8601 basic format</i> with hours field and optional minutes field.
+ *         The ISO8601 UTC indicator "Z" is used when local time offset is 0.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">2</td>
+ *         <td>-0800<br>
+ *         Z</td>
+ *         <td>The <i>ISO8601 basic format</i> with hours and minutes fields.
+ *         The ISO8601 UTC indicator "Z" is used when local time offset is 0.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">3</td>
+ *         <td>-08:00<br>
+ *         Z</td>
+ *         <td>The <i>ISO8601 extended format</i> with hours and minutes fields.
+ *         The ISO8601 UTC indicator "Z" is used when local time offset is 0.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">4</td>
+ *         <td>-0800<br>
+ *         -075258<br>
+ *         Z</td>
+ *         <td>The <i>ISO8601 basic format</i> with hours, minutes and optional seconds fields.
+ *         (Note: The seconds field is not supported by the ISO8601 specification.)
+ *         The ISO8601 UTC indicator "Z" is used when local time offset is 0.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">5</td>
+ *         <td>-08:00<br>
+ *         -07:52:58<br>
+ *         Z</td>
+ *         <td>The <i>ISO8601 extended format</i> with hours, minutes and optional seconds fields.
+ *         (Note: The seconds field is not supported by the ISO8601 specification.)
+ *         The ISO8601 UTC indicator "Z" is used when local time offset is 0.</td>
+ *     </tr>
+ *     <tr>
+ *         <td rowspan="5" style="text-align: center">x</td>
+ *         <td style="text-align: center">1</td>
+ *         <td>-08<br>
+ *         +0530</td>
+ *         <td>The <i>ISO8601 basic format</i> with hours field and optional minutes field.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">2</td>
+ *         <td>-0800</td>
+ *         <td>The <i>ISO8601 basic format</i> with hours and minutes fields.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">3</td>
+ *         <td>-08:00</td>
+ *         <td>The <i>ISO8601 extended format</i> with hours and minutes fields.</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">4</td>
+ *         <td>-0800<br>
+ *         -075258</td>
+ *         <td>The <i>ISO8601 basic format</i> with hours, minutes and optional seconds fields.
+ *         (Note: The seconds field is not supported by the ISO8601 specification.)</td>
+ *     </tr>
+ *     <tr>
+ *         <td style="text-align: center">5</td>
+ *         <td>-08:00<br>
+ *         -07:52:58</td>
+ *         <td>The <i>ISO8601 extended format</i> with hours, minutes and optional seconds fields.
+ *         (Note: The seconds field is not supported by the ISO8601 specification.)</td>
+ *     </tr>
+ * </table>
+ * 
  * </blockquote>
- * <tt><b>*</b></tt> These items are not supported by Java's SimpleDateFormat.<br>
- * <tt><b>&#x2020;</b></tt> ICU interprets a single 'y' differently than Java.</p>
- * <p>
- * The count of pattern letters determine the format.
- * <p>
- * <strong>(Text)</strong>: 4 or more pattern letters--use full form,
- * &lt; 4--use short or abbreviated form if one exists.
- * <p>
- * <strong>(Number)</strong>: the minimum number of digits. Shorter
- * numbers are zero-padded to this amount. Year is handled specially;
- * that is, if the count of 'y' is 2, the Year will be truncated to 2 digits.
- * (e.g., if "yyyy" produces "1997", "yy" produces "97".)
- * Unlike other fields, fractional seconds are padded on the right with zero.
- * <p>
- * <strong>(Text & Number)</strong>: 3 or over, use text, otherwise use number.
  * <p>
  * Any characters in the pattern that are not in the ranges of ['a'..'z']
  * and ['A'..'Z'] will be treated as quoted text. For instance, characters
@@ -216,6 +700,7 @@ import com.ibm.icu.util.ULocale.Category;
  * @see          DateFormat
  * @see          DateFormatSymbols
  * @see          DecimalFormat
+ * @see          TimeZoneFormat
  * @author       Mark Davis, Chen-Lieh Huang, Alan Liu
  * @stable ICU 2.0
  */
@@ -228,7 +713,8 @@ public class SimpleDateFormat extends DateFormat {
     // the internal serial version which says which version was written
     // - 0 (default) for version up to JDK 1.1.3
     // - 1 for version from JDK 1.1.4, which includes a new field
-    static final int currentSerialVersion = 1;
+    // - 2 we write additional int for capitalizationContext
+    static final int currentSerialVersion = 2;
 
     static boolean DelayedHebrewMonthCheck = false;
 
@@ -263,16 +749,20 @@ public class SimpleDateFormat extends DateFormat {
      */
     private static final int[] PATTERN_CHAR_TO_LEVEL =
     {
-    //       A   B   C   D    E   F   G    H   I   J   K   L    M   N   O
-        -1, 40, -1, -1, 20,  30, 30,  0,  50, -1, -1, 50, 20,  20, -1, -1,
-    //   P   Q   R    S   T   U  V   W   X   Y  Z
-        -1, 20, -1,  80, -1, -1, 0, 30, -1, 10, 0, -1, -1, -1, -1, -1,
-    //       a   b   c   d    e   f  g   h   i   j    k   l    m   n   o
-        -1, 40, -1, 30,  30, 30, -1, 0, 50, -1, -1,  50, -1,  60, -1, -1,
-    //   p   q   r    s   t   u  v   w   x    y  z
-        -1, 20, -1,  70, -1, 10, 0, 20, -1,  10, 0, -1, -1, -1, -1, -1
+    //       A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
+        -1, 40, -1, -1, 20, 30, 30,  0, 50, -1, -1, 50, 20, 20, -1,  0,
+    //   P   Q   R   S   T   U   V   W   X   Y   Z
+        -1, 20, -1, 80, -1, 10,  0, 30,  0, 10,  0, -1, -1, -1, -1, -1,
+    //       a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
+        -1, 40, -1, 30, 30, 30, -1,  0, 50, -1, -1, 50, -1, 60, -1, -1,
+    //   p   q   r   s   t   u   v   w   x   y   z
+        -1, 20, -1, 70, -1, 10,  0, 20,  0, 10,  0, -1, -1, -1, -1, -1
     };
 
+    // When calendar uses hebr numbering (i.e. he@calendar=hebrew),
+    // offset the years within the current millenium down to 1-999
+    private static final int HEBREW_CAL_CUR_MILLENIUM_START_YEAR = 5000;
+    private static final int HEBREW_CAL_CUR_MILLENIUM_END_YEAR = 6000;
 
     /**
      * The version of the serialized data on the stream.  Possible values:
@@ -281,6 +771,8 @@ public class SimpleDateFormat extends DateFormat {
      * has no <code>defaultCenturyStart</code> on stream.
      * <li><b>1</b> JDK 1.1.4 or later.  This version adds
      * <code>defaultCenturyStart</code>.
+     * <li><b>2</b> This version writes an additional int for
+     * <code>capitalizationContext</code>.
      * </ul>
      * When streaming out this class, the most recent format
      * and the highest allowable <code>serialVersionOnStream</code>
@@ -342,8 +834,7 @@ public class SimpleDateFormat extends DateFormat {
 
     // We need to preserve time zone type when parsing specific
     // time zone text (xxx Standard Time vs xxx Daylight Time)
-    private static final int TZTYPE_UNK = 0, TZTYPE_STD = 1, TZTYPE_DST = 2;
-    private transient int tztype = TZTYPE_UNK;
+    private transient TimeType tztype = TimeType.UNKNOWN;
 
     private static final int millisPerHour = 60 * 60 * 1000;
 
@@ -367,6 +858,30 @@ public class SimpleDateFormat extends DateFormat {
      */
     private volatile TimeZoneFormat tzFormat;
 
+    /*
+     *  Capitalization setting, introduced in ICU 50
+     *  Special serialization, see writeObject & readObject below
+     */
+    private transient DisplayContext capitalizationSetting;
+
+    /*
+     *  Old defaultCapitalizationContext field
+     *  from ICU 49.1:
+     */
+    //private ContextValue defaultCapitalizationContext;
+    /**
+     *  Old ContextValue enum, preserved only to avoid
+     *  deserialization errs from ICU 49.1.
+     */
+    @SuppressWarnings("unused")
+    private enum ContextValue {
+        UNKNOWN,
+        CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,
+        CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE,
+        CAPITALIZATION_FOR_UI_LIST_OR_MENU,
+        CAPITALIZATION_FOR_STANDALONE
+    }
+
     /**
      * Constructs a SimpleDateFormat using the default pattern for the default <code>FORMAT</code>
      * locale.  <b>Note:</b> Not all locales support SimpleDateFormat; for full
@@ -479,7 +994,7 @@ public class SimpleDateFormat extends DateFormat {
     }
 
     /**
-     * Creates an instance of SimpleDateForamt for the given format configuration
+     * Creates an instance of SimpleDateFormat for the given format configuration
      * @param formatConfig the format configuration
      * @return A SimpleDateFormat instance
      * @internal
@@ -533,6 +1048,8 @@ public class SimpleDateFormat extends DateFormat {
         if (override != null) {
            initNumberFormatters(locale);
         }
+        
+        capitalizationSetting = DisplayContext.CAPITALIZATION_NONE;
 
     }
 
@@ -695,7 +1212,7 @@ public class SimpleDateFormat extends DateFormat {
             calendar.setTimeZone(cal.getTimeZone());
             cal = calendar;
         }
-        StringBuffer result = format(cal, toAppendTo, pos, null);
+        StringBuffer result = format(cal, capitalizationSetting, toAppendTo, pos, null);
         if (backupTZ != null) {
             // Restore the original time zone
             calendar.setTimeZone(backupTZ);
@@ -705,8 +1222,8 @@ public class SimpleDateFormat extends DateFormat {
 
     // The actual method to format date. If List attributes is not null,
     // then attribute information will be recorded.
-    private StringBuffer format(Calendar cal, StringBuffer toAppendTo,
-            FieldPosition pos, List<FieldPosition> attributes) {
+    private StringBuffer format(Calendar cal, DisplayContext capitalizationContext,
+            StringBuffer toAppendTo, FieldPosition pos, List<FieldPosition> attributes) {
         // Initialize
         pos.setBeginIndex(0);
         pos.setEndIndex(0);
@@ -727,10 +1244,11 @@ public class SimpleDateFormat extends DateFormat {
                     start = toAppendTo.length();
                 }
                 if (useFastFormat) {
-                    subFormat(toAppendTo, item.type, item.length, toAppendTo.length(), pos, cal);
+                    subFormat(toAppendTo, item.type, item.length, toAppendTo.length(),
+                              i, capitalizationContext, pos, cal);
                 } else {
-                    toAppendTo.append(subFormat(item.type, item.length, toAppendTo.length(), pos,
-                                                formatData, cal));
+                    toAppendTo.append(subFormat(item.type, item.length, toAppendTo.length(),
+                                                i, capitalizationContext, pos, cal));
                 }
                 if (attributes != null) {
                     // Check the sub format length
@@ -755,13 +1273,13 @@ public class SimpleDateFormat extends DateFormat {
     private static final int[] PATTERN_CHAR_TO_INDEX =
     {
     //       A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
-        -1, 22, -1, -1, 10,  9, 11,  0,  5, -1, -1, 16, 26,  2, -1, -1,
+        -1, 22, -1, -1, 10,  9, 11,  0,  5, -1, -1, 16, 26,  2, -1, 31,
     //   P   Q   R   S   T   U   V   W   X   Y   Z
-        -1, 27, -1,  8, -1, -1, 29, 13, -1, 18, 23, -1, -1, -1, -1, -1,
+        -1, 27, -1,  8, -1, 30, 29, 13, 32, 18, 23, -1, -1, -1, -1, -1,
     //       a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
         -1, 14, -1, 25,  3, 19, -1, 21, 15, -1, -1,  4, -1,  6, -1, -1,
     //   p   q   r   s   t   u   v   w   x   y   z
-        -1, 28, -1,  7, -1, 20, 24, 12, -1,  1, 17, -1, -1, -1, -1, -1
+        -1, 28, -1,  7, -1, 20, 24, 12, 33,  1, 17, -1, -1, -1, -1, -1
     };
 
     // Map pattern character index to Calendar field number
@@ -780,6 +1298,9 @@ public class SimpleDateFormat extends DateFormat {
         /*L*/   Calendar.MONTH,
         /*Qq*/  Calendar.MONTH, Calendar.MONTH,
         /*V*/   Calendar.ZONE_OFFSET,
+        /*U*/   Calendar.YEAR,
+        /*O*/   Calendar.ZONE_OFFSET,
+        /*Xx*/  Calendar.ZONE_OFFSET, Calendar.ZONE_OFFSET,
     };
 
     // Map pattern character index to DateFormat field number
@@ -797,6 +1318,9 @@ public class SimpleDateFormat extends DateFormat {
         /*L*/   DateFormat.STANDALONE_MONTH_FIELD,
         /*Qq*/  DateFormat.QUARTER_FIELD, DateFormat.STANDALONE_QUARTER_FIELD,
         /*V*/   DateFormat.TIMEZONE_SPECIAL_FIELD,
+        /*U*/   DateFormat.YEAR_NAME_FIELD,
+        /*O*/   DateFormat.TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD,
+        /*Xx*/  DateFormat.TIMEZONE_ISO_FIELD, DateFormat.TIMEZONE_ISO_LOCAL_FIELD,
     };
 
     // Map pattern character index to DateFormat.Field
@@ -814,6 +1338,9 @@ public class SimpleDateFormat extends DateFormat {
         /*L*/   DateFormat.Field.MONTH,
         /*Qq*/  DateFormat.Field.QUARTER, DateFormat.Field.QUARTER,
         /*V*/   DateFormat.Field.TIME_ZONE,
+        /*U*/   DateFormat.Field.YEAR,
+        /*O*/   DateFormat.Field.TIME_ZONE,
+        /*Xx*/  DateFormat.Field.TIME_ZONE, DateFormat.Field.TIME_ZONE,
     };
 
     /**
@@ -854,12 +1381,27 @@ public class SimpleDateFormat extends DateFormat {
         throws IllegalArgumentException
     {
         // Note: formatData is ignored
+        return subFormat(ch, count, beginOffset, 0, DisplayContext.CAPITALIZATION_NONE, pos, cal);
+    }
+
+     /**
+     * Formats a single field. This is the version called internally; it
+     * adds fieldNum and capitalizationContext parameters.
+     *
+     * @internal
+     * @deprecated This API is ICU internal only.
+     */
+    protected String subFormat(char ch, int count, int beginOffset,
+                               int fieldNum, DisplayContext capitalizationContext,
+                               FieldPosition pos,
+                               Calendar cal)
+    {
         StringBuffer buf = new StringBuffer();
-        subFormat(buf, ch, count, beginOffset, pos, cal);
+        subFormat(buf, ch, count, beginOffset, fieldNum, capitalizationContext, pos, cal);
         return buf.toString();
     }
 
-    /**
+   /**
      * Formats a single field; useFastFormat variant.  Reuses a
      * StringBuffer for results instead of creating a String on the
      * heap for each call.
@@ -874,6 +1416,7 @@ public class SimpleDateFormat extends DateFormat {
     @SuppressWarnings("fallthrough")
     protected void subFormat(StringBuffer buf,
                              char ch, int count, int beginOffset,
+                             int fieldNum, DisplayContext capitalizationContext,
                              FieldPosition pos,
                              Calendar cal) {
 
@@ -890,27 +1433,51 @@ public class SimpleDateFormat extends DateFormat {
         }
 
         if (patternCharIndex == -1) {
-            throw new IllegalArgumentException("Illegal pattern character " +
-                                               "'" + ch + "' in \"" +
-                                               pattern + '"');
+            if (ch == 'l') { // (SMALL LETTER L) deprecated placeholder for leap month marker, ignore
+                return;
+            } else {
+                throw new IllegalArgumentException("Illegal pattern character " +
+                                                   "'" + ch + "' in \"" +
+                                                   pattern + '"');
+            }
         }
 
         final int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
         int value = cal.get(field);
 
         NumberFormat currentNumberFormat = getNumberFormat(ch);
+        DateFormatSymbols.CapitalizationContextUsage capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.OTHER;
 
         switch (patternCharIndex) {
         case 0: // 'G' - ERA
-            if (count == 5) {
-                safeAppend(formatData.narrowEras, value, buf);
-            } else if (count == 4) {
-                safeAppend(formatData.eraNames, value, buf);
+            if ( cal.getType().equals("chinese") || cal.getType().equals("dangi") ) {
+                // moved from ChineseDateFormat
+                zeroPaddingNumber(currentNumberFormat, buf, value, 1, 9);
             } else {
-                safeAppend(formatData.eras, value, buf);
+                if (count == 5) {
+                    safeAppend(formatData.narrowEras, value, buf);
+                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.ERA_NARROW;
+                } else if (count == 4) {
+                    safeAppend(formatData.eraNames, value, buf);
+                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.ERA_WIDE;
+                } else {
+                    safeAppend(formatData.eras, value, buf);
+                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.ERA_ABBREV;
+                }
             }
             break;
+        case 30: // 'U' - YEAR_NAME_FIELD
+            if (formatData.shortYearNames != null && value <= formatData.shortYearNames.length) {
+                safeAppend(formatData.shortYearNames, value-1, buf);
+                break;
+            }
+            // else fall through to numeric year handling, do not break here 
         case 1: // 'y' - YEAR
+        case 18: // 'Y' - YEAR_WOY
+            if ( override != null && (override.compareTo("hebr") == 0 || override.indexOf("y=hebr") >= 0) &&
+                    value > HEBREW_CAL_CUR_MILLENIUM_START_YEAR && value < HEBREW_CAL_CUR_MILLENIUM_END_YEAR ) {
+                value -= HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
+            }
             /* According to the specification, if the number of pattern letters ('y') is 2,
              * the year is truncated to 2 digits; otherwise it is interpreted as a number.
              * But the original code process 'y', 'yy', 'yyy' in the same way. and process
@@ -924,6 +1491,7 @@ public class SimpleDateFormat extends DateFormat {
             }
             break;
         case 2: // 'M' - MONTH
+        case 26: // 'L' - STANDALONE MONTH
             if ( cal.getType().equals("hebrew")) {
                 boolean isLeap = HebrewCalendar.isLeapYear(cal.get(Calendar.YEAR));
                 if (isLeap && value == 6 && count >= 3 ) {
@@ -933,14 +1501,38 @@ public class SimpleDateFormat extends DateFormat {
                     value--; // Adjust the month number down 1 in Hebrew non-leap years, i.e. Adar is 6, not 7.
                 }
             }
+            int isLeapMonth = (formatData.leapMonthPatterns != null && formatData.leapMonthPatterns.length >= DateFormatSymbols.DT_MONTH_PATTERN_COUNT)?
+                     cal.get(Calendar.IS_LEAP_MONTH): 0;
+            // should consolidate the next section by using arrays of pointers & counts for the right symbols...
             if (count == 5) {
-                safeAppend(formatData.narrowMonths, value, buf);
+                if (patternCharIndex == 2) {
+                    safeAppendWithMonthPattern(formatData.narrowMonths, value, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_FORMAT_NARROW]: null);
+                } else {
+                    safeAppendWithMonthPattern(formatData.standaloneNarrowMonths, value, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_STANDALONE_NARROW]: null);
+                }
+                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.MONTH_NARROW;
             } else if (count == 4) {
-                safeAppend(formatData.months, value, buf);
+                if (patternCharIndex == 2) {
+                    safeAppendWithMonthPattern(formatData.months, value, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_FORMAT_WIDE]: null);
+                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.MONTH_FORMAT;
+                } else {
+                    safeAppendWithMonthPattern(formatData.standaloneMonths, value, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_STANDALONE_WIDE]: null);
+                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.MONTH_STANDALONE;
+                }
             } else if (count == 3) {
-                safeAppend(formatData.shortMonths, value, buf);
+                if (patternCharIndex == 2) {
+                    safeAppendWithMonthPattern(formatData.shortMonths, value, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_FORMAT_ABBREV]: null);
+                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.MONTH_FORMAT;
+                } else {
+                    safeAppendWithMonthPattern(formatData.standaloneShortMonths, value, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_STANDALONE_ABBREV]: null);
+                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.MONTH_STANDALONE;
+                }
             } else {
-                zeroPaddingNumber(currentNumberFormat,buf, value+1, count, maxIntCount);
+                StringBuffer monthNumber = new StringBuffer();
+                zeroPaddingNumber(currentNumberFormat, monthNumber, value+1, count, maxIntCount);
+                String[] monthNumberStrings = new String[1];
+                monthNumberStrings[0] = monthNumber.toString();
+                safeAppendWithMonthPattern(monthNumberStrings, 0, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_NUMERIC]: null);
             }
             break;
         case 4: // 'k' - HOUR_OF_DAY (1..24)
@@ -982,10 +1574,16 @@ public class SimpleDateFormat extends DateFormat {
         case 9: // 'E' - DAY_OF_WEEK
             if (count == 5) {
                 safeAppend(formatData.narrowWeekdays, value, buf);
+                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_NARROW;
             } else if (count == 4) {
                 safeAppend(formatData.weekdays, value, buf);
+                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_FORMAT;
+            } else if (count == 6 && formatData.shorterWeekdays != null) {
+                safeAppend(formatData.shorterWeekdays, value, buf);
+                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_FORMAT;
             } else {// count <= 3, use abbreviated form if exists
                 safeAppend(formatData.shortWeekdays, value, buf);
+                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_FORMAT;
             }
             break;
         case 14: // 'a' - AM_PM
@@ -1000,34 +1598,105 @@ public class SimpleDateFormat extends DateFormat {
                 zeroPaddingNumber(currentNumberFormat,buf, value, count, maxIntCount);
             }
             break;
-        case 17: // 'z' - ZONE_OFFSET
+
+        case 17: // 'z' - TIMEZONE_FIELD
             if (count < 4) {
                 // "z", "zz", "zzz"
-                result = tzFormat().format(Style.SPECIFIC_SHORT_COMMONLY_USED, tz, date);
+                result = tzFormat().format(Style.SPECIFIC_SHORT, tz, date);
+                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.METAZONE_SHORT;
             } else {
                 result = tzFormat().format(Style.SPECIFIC_LONG, tz, date);
+                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.METAZONE_LONG;
             }
             buf.append(result);
             break;
-        case 23: // 'Z' - TIMEZONE_RFC
-        {
+        case 23: // 'Z' - TIMEZONE_RFC_FIELD
             if (count < 4) {
-                // RFC822 format
-                result = tzFormat().format(Style.RFC822, tz, date);
+                // RFC822 format - equivalent to ISO 8601 local offset fixed width format
+                result = tzFormat().format(Style.ISO_BASIC_LOCAL_FULL, tz, date);
+            } else if (count == 5) {
+                // ISO 8601 extended format
+                result = tzFormat().format(Style.ISO_EXTENDED_FULL, tz, date);
             } else {
                 // long form, localized GMT pattern
                 result = tzFormat().format(Style.LOCALIZED_GMT, tz, date);
             }
                 buf.append(result);
             break;
-            }
-        case 24: // 'v' - TIMEZONE_GENERIC
+        case 24: // 'v' - TIMEZONE_GENERIC_FIELD
             if (count == 1) {
                 // "v"
                 result = tzFormat().format(Style.GENERIC_SHORT, tz, date);
+                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.METAZONE_SHORT;
             } else if (count == 4) {
                 // "vvvv"
                 result = tzFormat().format(Style.GENERIC_LONG, tz, date);
+                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.METAZONE_LONG;
+            }
+            buf.append(result);
+            break;
+        case 29: // 'V' - TIMEZONE_SPECIAL_FIELD
+            if (count == 1) {
+                // "V"
+                result = tzFormat().format(Style.ZONE_ID_SHORT, tz, date);
+            } else if (count == 2) {
+                // "VV"
+                result = tzFormat().format(Style.ZONE_ID, tz, date);
+            } else if (count == 3) {
+                // "VVV"
+                result = tzFormat().format(Style.EXEMPLAR_LOCATION, tz, date);
+            } else if (count == 4) {
+                // "VVVV"
+                result = tzFormat().format(Style.GENERIC_LOCATION, tz, date);
+                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.ZONE_LONG;
+            }
+            buf.append(result);
+            break;
+        case 31: // 'O' - TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD
+            if (count == 1) {
+                // "O" - Short Localized GMT format
+                result = tzFormat().format(Style.LOCALIZED_GMT_SHORT, tz, date);
+            } else if (count == 4) {
+                // "OOOO" - Localized GMT format
+                result = tzFormat().format(Style.LOCALIZED_GMT, tz, date);
+            }
+            buf.append(result);
+            break;
+        case 32: // 'X' - TIMEZONE_ISO_FIELD
+            if (count == 1) {
+                // "X" - ISO Basic/Short
+                result = tzFormat().format(Style.ISO_BASIC_SHORT, tz, date);
+            } else if (count == 2) {
+                // "XX" - ISO Basic/Fixed
+                result = tzFormat().format(Style.ISO_BASIC_FIXED, tz, date);
+            } else if (count == 3) {
+                // "XXX" - ISO Extended/Fixed
+                result = tzFormat().format(Style.ISO_EXTENDED_FIXED, tz, date);
+            } else if (count == 4) {
+                // "XXXX" - ISO Basic/Optional second field
+                result = tzFormat().format(Style.ISO_BASIC_FULL, tz, date);
+            } else if (count == 5) {
+                // "XXXXX" - ISO Extended/Optional second field
+                result = tzFormat().format(Style.ISO_EXTENDED_FULL, tz, date);
+            }
+            buf.append(result);
+            break;
+        case 33: // 'x' - TIMEZONE_ISO_LOCAL_FIELD
+            if (count == 1) {
+                // "x" - ISO Local Basic/Short
+                result = tzFormat().format(Style.ISO_BASIC_LOCAL_SHORT, tz, date);
+            } else if (count == 2) {
+                // "x" - ISO Local Basic/Fixed
+                result = tzFormat().format(Style.ISO_BASIC_LOCAL_FIXED, tz, date);
+            } else if (count == 3) {
+                // "xxx" - ISO Local Extended/Fixed
+                result = tzFormat().format(Style.ISO_EXTENDED_LOCAL_FIXED, tz, date);
+            } else if (count == 4) {
+                // "xxxx" - ISO Local Basic/Optional second field
+                result = tzFormat().format(Style.ISO_BASIC_LOCAL_FULL, tz, date);
+            } else if (count == 5) {
+                // "xxxxx" - ISO Local Extended/Optional second field
+                result = tzFormat().format(Style.ISO_EXTENDED_LOCAL_FULL, tz, date);
             }
             buf.append(result);
             break;
@@ -1042,21 +1711,16 @@ public class SimpleDateFormat extends DateFormat {
             value = cal.get(Calendar.DAY_OF_WEEK);
             if (count == 5) {
                 safeAppend(formatData.standaloneNarrowWeekdays, value, buf);
+                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_NARROW;
             } else if (count == 4) {
                 safeAppend(formatData.standaloneWeekdays, value, buf);
+                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_STANDALONE;
+            } else if (count == 6 && formatData.standaloneShorterWeekdays != null) {
+                safeAppend(formatData.standaloneShorterWeekdays, value, buf);
+                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_STANDALONE;
             } else { // count == 3
                 safeAppend(formatData.standaloneShortWeekdays, value, buf);
-            }
-            break;
-        case 26: // 'L' - STANDALONE MONTH
-            if (count == 5) {
-                safeAppend(formatData.standaloneNarrowMonths, value, buf);
-            } else if (count == 4) {
-                safeAppend(formatData.standaloneMonths, value, buf);
-            } else if (count == 3) {
-                safeAppend(formatData.standaloneShortMonths, value, buf);
-            } else {
-                zeroPaddingNumber(currentNumberFormat,buf, value+1, count, maxIntCount);
+                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_STANDALONE;
             }
             break;
         case 27: // 'Q' - QUARTER
@@ -1077,16 +1741,6 @@ public class SimpleDateFormat extends DateFormat {
                 zeroPaddingNumber(currentNumberFormat,buf, (value/3)+1, count, maxIntCount);
             }
             break;
-        case 29: // 'V' - TIMEZONE_SPECIAL
-            if (count == 1) {
-                // "V"
-                result = tzFormat().format(Style.SPECIFIC_SHORT, tz, date);
-            } else if (count == 4) {
-                // "VVVV"
-                result = tzFormat().format(Style.GENERIC_LOCATION, tz, date);
-            }
-            buf.append(result);
-            break;
         default:
             // case 3: // 'd' - DATE
             // case 5: // 'H' - HOUR_OF_DAY (0..23)
@@ -1097,7 +1751,6 @@ public class SimpleDateFormat extends DateFormat {
             // case 12: // 'w' - WEEK_OF_YEAR
             // case 13: // 'W' - WEEK_OF_MONTH
             // case 16: // 'K' - HOUR (0..11)
-            // case 18: // 'Y' - YEAR_WOY
             // case 20: // 'u' - EXTENDED_YEAR
             // case 21: // 'g' - JULIAN_DAY
             // case 22: // 'A' - MILLISECONDS_IN_DAY
@@ -1106,6 +1759,33 @@ public class SimpleDateFormat extends DateFormat {
             break;
         } // switch (patternCharIndex)
 
+        if (fieldNum == 0) {
+            boolean titlecase = false;
+            if (capitalizationContext != null) {
+                switch (capitalizationContext) {
+                    case CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE:
+                        titlecase = true;
+                        break;
+                    case CAPITALIZATION_FOR_UI_LIST_OR_MENU:
+                    case CAPITALIZATION_FOR_STANDALONE:
+                        if (formatData.capitalization != null) {
+                             boolean[] transforms = formatData.capitalization.get(capContextUsageType);
+                            titlecase = (capitalizationContext==DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU)?
+                                        transforms[0]: transforms[1];
+                        }
+                        break;
+                    default:
+                       break;
+                }
+            }
+            if (titlecase) {
+                String firstField = buf.substring(bufstart); // bufstart or beginOffset, should be the same
+                String firstFieldTitleCase = UCharacter.toTitleCase(locale, firstField, null,
+                                                     UCharacter.TITLECASE_NO_LOWERCASE | UCharacter.TITLECASE_NO_BREAK_ADJUSTMENT);
+                buf.replace(bufstart, buf.length(), firstFieldTitleCase);
+            }
+        }
+
         // Set the FieldPosition (for the first occurrence only)
         if (pos.getBeginIndex() == pos.getEndIndex()) {
             if (pos.getField() == PATTERN_INDEX_TO_DATE_FORMAT_FIELD[patternCharIndex]) {
@@ -1125,6 +1805,16 @@ public class SimpleDateFormat extends DateFormat {
         }
     }
 
+    private static void safeAppendWithMonthPattern(String[] array, int value, StringBuffer appendTo, String monthPattern) {
+        if (array != null && value >= 0 && value < array.length) {
+            if (monthPattern == null) {
+                appendTo.append(array[value]);
+            } else {
+                appendTo.append(MessageFormat.format(monthPattern, array[value]));
+            }
+        }
+    }
+
     /*
      * PatternItem store parsed date/time field pattern information.
      */
@@ -1367,7 +2057,7 @@ public class SimpleDateFormat extends DateFormat {
         int start = pos;
 
         // Reset tztype
-        tztype = TZTYPE_UNK;
+        tztype = TimeType.UNKNOWN;
         boolean[] ambiguousYear = { false };
 
         // item index for the first numeric field within a contiguous numeric run
@@ -1376,6 +2066,11 @@ public class SimpleDateFormat extends DateFormat {
         int numericFieldLength = 0;
         // start index of numeric text run in the input text
         int numericStartPos = 0;
+        
+        MessageFormat numericLeapMonthFormatter = null;
+        if (formatData.leapMonthPatterns != null && formatData.leapMonthPatterns.length >= DateFormatSymbols.DT_MONTH_PATTERN_COUNT) {
+            numericLeapMonthFormatter = new MessageFormat(formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_NUMERIC], locale);
+        }
 
         Object[] items = getPatternItems();
         int i = 0;
@@ -1412,7 +2107,7 @@ public class SimpleDateFormat extends DateFormat {
 
                     // Parse a numeric field
                     pos = subParse(text, pos, field.type, len,
-                            true, false, ambiguousYear, cal);
+                            true, false, ambiguousYear, cal, numericLeapMonthFormatter);
 
                     if (pos < 0) {
                         // If the parse fails anywhere in the numeric run, back up to the
@@ -1433,13 +2128,13 @@ public class SimpleDateFormat extends DateFormat {
                         continue;
                     }
 
-                } else {
+                } else if (field.type != 'l') { // (SMALL LETTER L) obsolete pattern char just gets ignored
                     // Handle a non-numeric field or a non-abutting numeric field
                     numericFieldStart = -1;
 
                     int s = pos;
                     pos = subParse(text, pos, field.type, field.length,
-                            false, true, ambiguousYear, cal);
+                            false, true, ambiguousYear, cal, numericLeapMonthFormatter);
                     
                     if (pos < 0) {
                         if (pos == ISOSpecialEra) {
@@ -1448,8 +2143,22 @@ public class SimpleDateFormat extends DateFormat {
 
                             if (i+1 < items.length) { 
                                 
+                                String patl = null;
+                                // if it will cause a class cast exception to String, we can't use it                                
+                                try {
+                                    patl = (String)items[i+1];
+                                } catch(ClassCastException cce) {
+                                    parsePos.setIndex(start);
+                                    parsePos.setErrorIndex(s);
+                                    if (backupTZ != null) {
+                                        calendar.setTimeZone(backupTZ);
+                                    }
+                                    return;
+                                }                                
+                                
                                 // get next item in pattern
-                                String patl = (String)items[i+1];
+                                if(patl == null)
+                                    patl = (String)items[i+1];
                                 int plen = patl.length();
                                 int idx=0;
                                 
@@ -1484,33 +2193,9 @@ public class SimpleDateFormat extends DateFormat {
             } else {
                 // Handle literal pattern text literal
                 numericFieldStart = -1;
-
-                String patl = (String)items[i];
-                int plen = patl.length();
-                int tlen = text.length();
-                int idx = 0;
-                while (idx < plen && pos < tlen) {
-                    char pch = patl.charAt(idx);
-                    char ich = text.charAt(pos);
-                    if (PatternProps.isWhiteSpace(pch)
-                        && PatternProps.isWhiteSpace(ich)) {
-                        // White space characters found in both patten and input.
-                        // Skip contiguous white spaces.
-                        while ((idx + 1) < plen &&
-                                PatternProps.isWhiteSpace(patl.charAt(idx + 1))) {
-                             ++idx;
-                        }
-                        while ((pos + 1) < tlen &&
-                                PatternProps.isWhiteSpace(text.charAt(pos + 1))) {
-                             ++pos;
-                        }
-                    } else if (pch != ich) {
-                        break;
-                    }
-                    ++idx;
-                    ++pos;
-                }
-                if (idx != plen) {
+                boolean[] complete = new boolean[1];
+                pos = matchLiteral(text, pos, items, i, complete);
+                if (!complete[0]) {
                     // Set the position of mismatch
                     parsePos.setIndex(start);
                     parsePos.setErrorIndex(pos);
@@ -1522,6 +2207,18 @@ public class SimpleDateFormat extends DateFormat {
             }
             ++i;
         }
+        
+        // Special hack for trailing "." after non-numeric field.
+        if (pos < text.length()) {
+            char extra = text.charAt(pos);
+            if (extra == '.' && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_WHITESPACE) && items.length != 0) {
+                // only do if the last field is not numeric
+                Object lastItem = items[items.length - 1];
+                if (lastItem instanceof PatternItem && !((PatternItem)lastItem).isNumeric) {
+                    pos++; // skip the extra "."
+                }
+            }
+        }
 
         // At this point the fields of Calendar have been set.  Calendar
         // will fill in default values for missing fields when the time
@@ -1552,7 +2249,7 @@ public class SimpleDateFormat extends DateFormat {
         // front or the back of the default century.  This only works because we adjust
         // the year correctly to start with in other cases -- see subParse().
         try {
-            if (ambiguousYear[0] || tztype != TZTYPE_UNK) {
+            if (ambiguousYear[0] || tztype != TimeType.UNKNOWN) {
                 // We need a copy of the fields, and we need to avoid triggering a call to
                 // complete(), which will recalculate the fields.  Since we can't access
                 // the fields[] array in Calendar, we clone the entire object.  This will
@@ -1566,7 +2263,7 @@ public class SimpleDateFormat extends DateFormat {
                         cal.set(Calendar.YEAR, getDefaultCenturyStartYear() + 100);
                     }
                 }
-                if (tztype != TZTYPE_UNK) {
+                if (tztype != TimeType.UNKNOWN) {
                     copy = (Calendar)cal.clone();
                     TimeZone tz = copy.getTimeZone();
                     BasicTimeZone btz = null;
@@ -1583,7 +2280,7 @@ public class SimpleDateFormat extends DateFormat {
                     // matches the rule used by the parsed time zone.
                     int[] offsets = new int[2];
                     if (btz != null) {
-                        if (tztype == TZTYPE_STD) {
+                        if (tztype == TimeType.STANDARD) {
                             btz.getOffsetFromLocal(localMillis,
                                     BasicTimeZone.LOCAL_STD, BasicTimeZone.LOCAL_STD, offsets);
                         } else {
@@ -1595,8 +2292,8 @@ public class SimpleDateFormat extends DateFormat {
                         // but following code work in most case.
                         tz.getOffset(localMillis, true, offsets);
 
-                        if (tztype == TZTYPE_STD && offsets[1] != 0
-                            || tztype == TZTYPE_DST && offsets[1] == 0) {
+                        if (tztype == TimeType.STANDARD && offsets[1] != 0
+                            || tztype == TimeType.DAYLIGHT && offsets[1] == 0) {
                             // Roll back one day and try it again.
                             // Note: This code assumes 1. timezone transition only happens
                             // once within 24 hours at max
@@ -1609,7 +2306,7 @@ public class SimpleDateFormat extends DateFormat {
                     // Now, compare the results with parsed type, either standard or
                     // daylight saving time
                     int resolvedSavings = offsets[1];
-                    if (tztype == TZTYPE_STD) {
+                    if (tztype == TimeType.STANDARD) {
                         if (offsets[1] != 0) {
                             // Override DST_OFFSET = 0 in the result calendar
                             resolvedSavings = 0;
@@ -1698,6 +2395,86 @@ public class SimpleDateFormat extends DateFormat {
         }
     }
 
+    /**
+     * Matches text (starting at pos) with patl. Returns the new pos, and sets complete[0]
+     * if it matched the entire text. Whitespace sequences are treated as singletons.
+     * <p>If isLenient and if we fail to match the first time, some special hacks are put into place.
+     * <ul><li>we are between date and time fields, then one or more whitespace characters
+     * in the text are accepted instead.</li>
+     * <ul><li>we are after a non-numeric field, and the text starts with a ".", we skip it.</li>
+     * </ul>
+     */
+    private int matchLiteral(String text, int pos, Object[] items, int itemIndex, boolean[] complete) {
+        int originalPos = pos;
+        String patternLiteral = (String)items[itemIndex];
+        int plen = patternLiteral.length();
+        int tlen = text.length();
+        int idx = 0;
+        while (idx < plen && pos < tlen) {
+            char pch = patternLiteral.charAt(idx);
+            char ich = text.charAt(pos);
+            if (PatternProps.isWhiteSpace(pch)
+                && PatternProps.isWhiteSpace(ich)) {
+                // White space characters found in both patten and input.
+                // Skip contiguous white spaces.
+                while ((idx + 1) < plen &&
+                        PatternProps.isWhiteSpace(patternLiteral.charAt(idx + 1))) {
+                     ++idx;
+                }
+                while ((pos + 1) < tlen &&
+                        PatternProps.isWhiteSpace(text.charAt(pos + 1))) {
+                     ++pos;
+                }
+            } else if (pch != ich) {
+                if (ich == '.' && pos == originalPos && 0 < itemIndex && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_WHITESPACE)) {
+                    Object before = items[itemIndex-1];
+                    if (before instanceof PatternItem) {
+                        boolean isNumeric = ((PatternItem) before).isNumeric;
+                        if (!isNumeric) {
+                            ++pos; // just update pos
+                            continue;
+                        }
+                    }
+                } else if ((pch == ' ' || pch == '.') && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_WHITESPACE)) {
+                    ++idx;
+                    continue;
+                }
+                break;
+            }
+            ++idx;
+            ++pos;
+        }
+        complete[0] = idx == plen;
+        if (complete[0] == false && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_WHITESPACE) && 0 < itemIndex && itemIndex < items.length - 1) {
+            // If fully lenient, accept " "* for any text between a date and a time field
+            // We don't go more lenient, because we don't want to accept "12/31" for "12:31".
+            // People may be trying to parse for a date, then for a time.
+            if (originalPos < tlen) {
+                Object before = items[itemIndex-1];
+                Object after = items[itemIndex+1];
+                if (before instanceof PatternItem && after instanceof PatternItem) {
+                    char beforeType = ((PatternItem) before).type;
+                    char afterType = ((PatternItem) after).type;
+                    if (DATE_PATTERN_TYPE.contains(beforeType) != DATE_PATTERN_TYPE.contains(afterType)) {
+                        int newPos = originalPos;
+                        while (true) {
+                            char ich = text.charAt(newPos);
+                            if (!PatternProps.isWhiteSpace(ich)) {
+                                break;
+                            }
+                            ++newPos;
+                        }
+                        complete[0] = newPos > originalPos;
+                        pos = newPos;
+                    }
+                }
+            }
+        }
+        return pos;
+    }
+    
+    static final UnicodeSet DATE_PATTERN_TYPE = new UnicodeSet("[GyYuUQqMLlwWd]").freeze();
+
     /**
      * Attempt to match the text at a given position against an array of
      * strings.  Since multiple strings in the array may match (for
@@ -1709,6 +2486,7 @@ public class SimpleDateFormat extends DateFormat {
      * @param start where to start parsing.
      * @param field the date field being parsed.
      * @param data the string array to parsed.
+     * @param cal
      * @return the new start position if matching succeeded; a negative
      * number indicating matching failure, otherwise.  As a side effect,
      * sets the <code>cal</code> field <code>field</code> to the index
@@ -1716,6 +2494,31 @@ public class SimpleDateFormat extends DateFormat {
      * @stable ICU 2.0
      */
     protected int matchString(String text, int start, int field, String[] data, Calendar cal)
+    {
+        return matchString(text, start, field, data, null, cal);
+    }
+
+    /**
+     * Attempt to match the text at a given position against an array of
+     * strings.  Since multiple strings in the array may match (for
+     * example, if the array contains "a", "ab", and "abc", all will match
+     * the input string "abcd") the longest match is returned.  As a side
+     * effect, the given field of <code>cal</code> is set to the index
+     * of the best match, if there is one.
+     * @param text the time text being parsed.
+     * @param start where to start parsing.
+     * @param field the date field being parsed.
+     * @param data the string array to parsed.
+     * @param monthPattern leap month pattern, or null if none.
+     * @param cal
+     * @return the new start position if matching succeeded; a negative
+     * number indicating matching failure, otherwise.  As a side effect,
+     * sets the <code>cal</code> field <code>field</code> to the index
+     * of the best match, if matching succeeded.
+     * @internal
+     * @deprecated This API is ICU internal only.
+     */
+    private int matchString(String text, int start, int field, String[] data, String monthPattern, Calendar cal)
     {
         int i = 0;
         int count = data.length;
@@ -1727,24 +2530,58 @@ public class SimpleDateFormat extends DateFormat {
         // We keep track of the longest match, and return that.  Note that this
         // unfortunately requires us to test all array elements.
         int bestMatchLength = 0, bestMatch = -1;
+        int isLeapMonth = 0;
+        int matchLength = 0;
+
         for (; i<count; ++i)
             {
                 int length = data[i].length();
                 // Always compare if we have no match yet; otherwise only compare
                 // against potentially better matches (longer strings).
                 if (length > bestMatchLength &&
-                    text.regionMatches(true, start, data[i], 0, length))
+                    (matchLength = regionMatchesWithOptionalDot(text, start, data[i], length)) >= 0)
                     {
                         bestMatch = i;
-                        bestMatchLength = length;
+                        bestMatchLength = matchLength;
+                        isLeapMonth = 0;
                     }
+                if (monthPattern != null) {
+                    String leapMonthName = MessageFormat.format(monthPattern, data[i]);
+                    length = leapMonthName.length();
+                    if (length > bestMatchLength &&
+                        (matchLength = regionMatchesWithOptionalDot(text, start, leapMonthName, length)) >= 0)
+                        {
+                            bestMatch = i;
+                            bestMatchLength = matchLength;
+                            isLeapMonth = 1;
+                        }
+                 }
             }
         if (bestMatch >= 0)
             {
+                if (field == Calendar.YEAR) {
+                    bestMatch++; // only get here for cyclic year names, which match 1-based years 1-60
+                }
                 cal.set(field, bestMatch);
+                if (monthPattern != null) {
+                    cal.set(Calendar.IS_LEAP_MONTH, isLeapMonth);
+                }
                 return start + bestMatchLength;
             }
-        return -start;
+        return ~start;
+    }
+
+    private int regionMatchesWithOptionalDot(String text, int start, String data, int length) {
+        boolean matches = text.regionMatches(true, start, data, 0, length);
+        if (matches) {
+            return length;
+        }
+        if (data.length() > 0 && data.charAt(data.length()-1) == '.') {
+            if (text.regionMatches(true, start, data, 0, length-1)) {
+                return length - 1;
+            }
+        }
+        return -1;
     }
 
     /**
@@ -1774,14 +2611,16 @@ public class SimpleDateFormat extends DateFormat {
         // We keep track of the longest match, and return that.  Note that this
         // unfortunately requires us to test all array elements.
         int bestMatchLength = 0, bestMatch = -1;
+        int matchLength = 0;
         for (; i<count; ++i) {
             int length = data[i].length();
             // Always compare if we have no match yet; otherwise only compare
             // against potentially better matches (longer strings).
             if (length > bestMatchLength &&
-                text.regionMatches(true, start, data[i], 0, length)) {
+                (matchLength = regionMatchesWithOptionalDot(text, start, data[i], length)) >= 0) {
+
                 bestMatch = i;
-                bestMatchLength = length;
+                bestMatchLength = matchLength;
             }
         }
 
@@ -1806,6 +2645,7 @@ public class SimpleDateFormat extends DateFormat {
      * and we should use the count to know when to stop parsing.
      * @param ambiguousYear return parameter; upon return, if ambiguousYear[0]
      * is true, then a two-digit year was parsed and may need to be readjusted.
+     * @param cal
      * @return the new start position if matching succeeded; a negative
      * number indicating matching failure, otherwise.  As a side effect,
      * set the appropriate field of <code>cal</code> with the parsed
@@ -1815,6 +2655,35 @@ public class SimpleDateFormat extends DateFormat {
     protected int subParse(String text, int start, char ch, int count,
                            boolean obeyCount, boolean allowNegative,
                            boolean[] ambiguousYear, Calendar cal)
+    {
+        return subParse(text, start, ch, count, obeyCount, allowNegative, ambiguousYear, cal, null);
+    }
+
+    /**
+     * Protected method that converts one field of the input string into a
+     * numeric field value in <code>cal</code>.  Returns -start (for
+     * ParsePosition) if failed.  Subclasses may override this method to
+     * modify or add parsing capabilities.
+     * @param text the time text to be parsed.
+     * @param start where to start parsing.
+     * @param ch the pattern character for the date field text to be parsed.
+     * @param count the count of a pattern character.
+     * @param obeyCount if true, then the next field directly abuts this one,
+     * and we should use the count to know when to stop parsing.
+     * @param ambiguousYear return parameter; upon return, if ambiguousYear[0]
+     * is true, then a two-digit year was parsed and may need to be readjusted.
+     * @param cal
+     * @param numericLeapMonthFormatter if non-null, used to parse numeric leap months. 
+     * @return the new start position if matching succeeded; a negative
+     * number indicating matching failure, otherwise.  As a side effect,
+     * set the appropriate field of <code>cal</code> with the parsed
+     * value.
+     * @internal
+     * @deprecated This API is ICU internal only.
+     */
+    private int subParse(String text, int start, char ch, int count,
+                           boolean obeyCount, boolean allowNegative,
+                           boolean[] ambiguousYear, Calendar cal, MessageFormat numericLeapMonthFormatter)
     {
         Number number = null;
         NumberFormat currentNumberFormat = null;
@@ -1829,18 +2698,23 @@ public class SimpleDateFormat extends DateFormat {
         }
 
         if (patternCharIndex == -1) {
-            return -start;
+            return ~start;
         }
 
         currentNumberFormat = getNumberFormat(ch);
 
         int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
+        
+        if (numericLeapMonthFormatter != null) {
+            numericLeapMonthFormatter.setFormatByArgumentIndex(0, currentNumberFormat);
+        }
+        boolean isChineseCalendar = ( cal.getType().equals("chinese") || cal.getType().equals("dangi") );
 
         // If there are any spaces here, skip over them.  If we hit the end
         // of the string, then fail.
         for (;;) {
             if (start >= text.length()) {
-                return -start;
+                return ~start;
             }
             int c = UTF16.charAt(text, start);
             if (!UCharacter.isUWhiteSpace(c) || !PatternProps.isWhiteSpace(c)) {
@@ -1854,47 +2728,79 @@ public class SimpleDateFormat extends DateFormat {
         // a number value.  We handle further, more generic cases below.  We need
         // to handle some of them here because some fields require extra processing on
         // the parsed value.
-        if (patternCharIndex == 4 /*HOUR_OF_DAY1_FIELD*/ ||
-            patternCharIndex == 15 /*HOUR1_FIELD*/ ||
-            (patternCharIndex == 2 /*MONTH_FIELD*/ && count <= 2) ||
-            patternCharIndex == 1 ||
-            patternCharIndex == 8)
+        if (patternCharIndex == 4 /*'k' HOUR_OF_DAY1_FIELD*/ ||
+            patternCharIndex == 15 /*'h' HOUR1_FIELD*/ ||
+            (patternCharIndex == 2 /*'M' MONTH_FIELD*/ && count <= 2) ||
+            (patternCharIndex == 26 /*'L' STAND_ALONE_MONTH*/ && count <= 2) ||
+            patternCharIndex == 1 /*'y' YEAR */ || patternCharIndex == 18 /*'Y' YEAR_WOY */ ||
+            patternCharIndex == 30 /*'U' YEAR_NAME_FIELD, falls back to numeric */ ||
+            (patternCharIndex == 0 /*'G' ERA */ && isChineseCalendar) ||
+            patternCharIndex == 8 /*'S' FRACTIONAL_SECOND */ )
             {
                 // It would be good to unify this with the obeyCount logic below,
                 // but that's going to be difficult.
-                if (obeyCount) {
-                        if ((start+count) > text.length()) return -start;
+                
+                boolean parsedNumericLeapMonth = false;
+                if (numericLeapMonthFormatter != null && (patternCharIndex == 2 || patternCharIndex == 26)) {
+                    // First see if we can parse month number with leap month pattern
+                    Object[] args = numericLeapMonthFormatter.parse(text, pos);
+                    if (args != null && pos.getIndex() > start && (args[0] instanceof Number)) {
+                        parsedNumericLeapMonth = true;
+                        number = (Number)args[0];
+                        cal.set(Calendar.IS_LEAP_MONTH, 1);
+                    } else {
+                        pos.setIndex(start);
+                        cal.set(Calendar.IS_LEAP_MONTH, 0);
+                   }
+                }
+                
+                if (!parsedNumericLeapMonth) {
+                    if (obeyCount) {
+                        if ((start+count) > text.length()) {
+                            return ~start;
+                        }
                         number = parseInt(text, count, pos, allowNegative,currentNumberFormat);
-                } else {
-                    number = parseInt(text, pos, allowNegative,currentNumberFormat);
+                    } else {
+                        number = parseInt(text, pos, allowNegative,currentNumberFormat);
+                    }
+                    if (number == null && patternCharIndex != 30) {
+                        return ~start;
+                    }
                 }
-                if (number == null) {
-                    return -start;
+
+                if (number != null) {
+                    value = number.intValue();
                 }
-                value = number.intValue();
             }
 
         switch (patternCharIndex)
             {
             case 0: // 'G' - ERA
+                if ( isChineseCalendar ) {
+                    // Numeric era handling moved from ChineseDateFormat,
+                    // If we didn't have a number, already returned -start above
+                    cal.set(Calendar.ERA, value);
+                    return pos.getIndex();
+                }
                 int ps = 0;
                 if (count == 5) {
-                    ps = matchString(text, start, Calendar.ERA, formatData.narrowEras, cal);
+                    ps = matchString(text, start, Calendar.ERA, formatData.narrowEras, null, cal);
                 } else if (count == 4) {
-                    ps = matchString(text, start, Calendar.ERA, formatData.eraNames, cal);
+                    ps = matchString(text, start, Calendar.ERA, formatData.eraNames, null, cal);
                 } else {
-                    ps = matchString(text, start, Calendar.ERA, formatData.eras, cal);
+                    ps = matchString(text, start, Calendar.ERA, formatData.eras, null, cal);
                 }
 
                 // check return position, if it equals -start, then matchString error
                 // special case the return code so we don't necessarily fail out until we 
                 // verify no year information also
-                if (ps == -start)
+                if (ps == ~start)
                     ps = ISOSpecialEra;
 
                 return ps;  
                 
             case 1: // 'y' - YEAR
+            case 18: // 'Y' - YEAR_WOY
                 // If there are 3 or more YEAR pattern characters, this indicates
                 // that the year value is to be treated literally, without any
                 // two-digit year adjustments (e.g., from "01" to 2001).  Otherwise
@@ -1902,7 +2808,10 @@ public class SimpleDateFormat extends DateFormat {
                 // century, for parsed strings from "00" to "99".  Any other string
                 // is treated literally:  "2250", "-1", "1", "002".
                 /* 'yy' is the only special case, 'y' is interpreted as number. [Richard/GCL]*/
-                if (count == 2 && (pos.getIndex() - start) == 2
+                /* Skip this for Chinese calendar, moved from ChineseDateFormat */
+                if ( override != null && (override.compareTo("hebr") == 0 || override.indexOf("y=hebr") >= 0) && value < 1000 ) {
+                    value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
+                } else if (count == 2 && (pos.getIndex() - start) == 2 && !isChineseCalendar
                     && UCharacter.isDigit(text.charAt(start))
                     && UCharacter.isDigit(text.charAt(start+1)))
                     {
@@ -1919,7 +2828,7 @@ public class SimpleDateFormat extends DateFormat {
                         value += (getDefaultCenturyStartYear()/100)*100 +
                             (value < ambiguousTwoDigitYear ? 100 : 0);
                     }
-                cal.set(Calendar.YEAR, value);
+                cal.set(field, value);
 
                 // Delayed checking for adjustment of Hebrew month numbers in non-leap years.
                 if (DelayedHebrewMonthCheck) {
@@ -1929,10 +2838,23 @@ public class SimpleDateFormat extends DateFormat {
                     DelayedHebrewMonthCheck = false;
                 }
                 return pos.getIndex();
+            case 30: // 'U' - YEAR_NAME_FIELD
+                if (formatData.shortYearNames != null) {
+                    int newStart = matchString(text, start, Calendar.YEAR, formatData.shortYearNames, null, cal);
+                    if (newStart > 0) {
+                        return newStart;
+                    }
+                }
+                if ( number != null && (getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC) || formatData.shortYearNames == null || value > formatData.shortYearNames.length) ) {
+                    cal.set(Calendar.YEAR, value);
+                    return pos.getIndex();
+                }
+                return ~start;
             case 2: // 'M' - MONTH
-                if (count <= 2) { // i.e., M or MM.
+            case 26: // 'L' - STAND_ALONE_MONTH
+                if (count <= 2) { // i.e., M/MM, L/LL
                     // Don't want to parse the month if it is a string
-                    // while pattern uses numeric style: M or MM.
+                    // while pattern uses numeric style: M/MM, L/LL.
                     // [We computed 'value' above.]
                     cal.set(Calendar.MONTH, value - 1);
                     // When parsing month numbers from the Hebrew Calendar, we might need
@@ -1950,36 +2872,23 @@ public class SimpleDateFormat extends DateFormat {
                     }
                     return pos.getIndex();
                 } else {
-                    // count >= 3 // i.e., MMM or MMMM
+                    // count >= 3 // i.e., MMM/MMMM or LLL/LLLL
                     // Want to be able to parse both short and long forms.
+                    boolean haveMonthPat = (formatData.leapMonthPatterns != null && formatData.leapMonthPatterns.length >= DateFormatSymbols.DT_MONTH_PATTERN_COUNT);
                     // Try count == 4 first:
-                    int newStart = matchString(text, start, Calendar.MONTH,
-                                               formatData.months, cal);
+                    int newStart = (patternCharIndex == 2)?
+                            matchString(text, start, Calendar.MONTH, formatData.months,
+                                    (haveMonthPat)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_FORMAT_WIDE]: null, cal):
+                            matchString(text, start, Calendar.MONTH, formatData.standaloneMonths,
+                                    (haveMonthPat)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_STANDALONE_WIDE]: null, cal);
                     if (newStart > 0) {
                         return newStart;
                     } else { // count == 4 failed, now try count == 3
-                        return matchString(text, start, Calendar.MONTH,
-                                           formatData.shortMonths, cal);
-                    }
-                }
-            case 26: // 'L' - STAND_ALONE_MONTH
-                if (count <= 2) { // i.e., M or MM.
-                    // Don't want to parse the month if it is a string
-                    // while pattern uses numeric style: M or MM.
-                    // [We computed 'value' above.]
-                    cal.set(Calendar.MONTH, value - 1);
-                    return pos.getIndex();
-                } else {
-                    // count >= 3 // i.e., MMM or MMMM
-                    // Want to be able to parse both short and long forms.
-                    // Try count == 4 first:
-                    int newStart = matchString(text, start, Calendar.MONTH,
-                                               formatData.standaloneMonths, cal);
-                    if (newStart > 0) {
-                        return newStart;
-                    } else { // count == 4 failed, now try count == 3
-                        return matchString(text, start, Calendar.MONTH,
-                                           formatData.standaloneShortMonths, cal);
+                        return (patternCharIndex == 2)?
+                                matchString(text, start, Calendar.MONTH, formatData.shortMonths,
+                                        (haveMonthPat)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_FORMAT_ABBREV]: null, cal):
+                                matchString(text, start, Calendar.MONTH, formatData.standaloneShortMonths,
+                                        (haveMonthPat)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_STANDALONE_ABBREV]: null, cal);
                     }
                 }
             case 4: // 'k' - HOUR_OF_DAY (1..24)
@@ -2003,36 +2912,36 @@ public class SimpleDateFormat extends DateFormat {
                         a *= 10;
                         i--;
                     }
-                    value = (value + (a>>1)) / a;
+                    value /= a;
                 }
                 cal.set(Calendar.MILLISECOND, value);
                 return pos.getIndex();
             case 9: { // 'E' - DAY_OF_WEEK
-                // Want to be able to parse both short and long forms.
-                // Try count == 4 (EEEE) first:
-                int newStart = matchString(text, start, Calendar.DAY_OF_WEEK,
-                                           formatData.weekdays, cal);
+                // Want to be able to parse at least wide, abbrev, short forms.
+                int newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.weekdays, null, cal); // try EEEE wide
                 if (newStart > 0) {
                     return newStart;
-                } else { // EEEE failed, now try EEE
-                    return matchString(text, start, Calendar.DAY_OF_WEEK,
-                                       formatData.shortWeekdays, cal);
+                } else if ((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.shortWeekdays, null, cal)) > 0) { // try EEE abbrev
+                    return newStart;
+                } else if (formatData.shorterWeekdays != null) {
+                    return matchString(text, start, Calendar.DAY_OF_WEEK, formatData.shorterWeekdays, null, cal); // try EEEEEE short
                 }
+                return newStart;
             }
             case 25: { // 'c' - STAND_ALONE_DAY_OF_WEEK
-                // Want to be able to parse both short and long forms.
-                // Try count == 4 (cccc) first:
-                int newStart = matchString(text, start, Calendar.DAY_OF_WEEK,
-                                           formatData.standaloneWeekdays, cal);
+                // Want to be able to parse at least wide, abbrev, short forms.
+                int newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.standaloneWeekdays, null, cal); // try cccc wide
                 if (newStart > 0) {
                     return newStart;
-                } else { // cccc failed, now try ccc
-                    return matchString(text, start, Calendar.DAY_OF_WEEK,
-                                       formatData.standaloneShortWeekdays, cal);
+                } else if ((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.standaloneShortWeekdays, null, cal)) > 0) { // try ccc abbrev
+                    return newStart;
+                } else if (formatData.standaloneShorterWeekdays != null) {
+                    return matchString(text, start, Calendar.DAY_OF_WEEK, formatData.standaloneShorterWeekdays, null, cal); // try cccccc short
                 }
+                return newStart;
             }
             case 14: // 'a' - AM_PM
-                return matchString(text, start, Calendar.AM_PM, formatData.ampms, cal);
+                return matchString(text, start, Calendar.AM_PM, formatData.ampms, null, cal);
             case 15: // 'h' - HOUR (1..12)
                 // [We computed 'value' above.]
                 if (value == cal.getLeastMaximum(Calendar.HOUR)+1) {
@@ -2043,34 +2952,26 @@ public class SimpleDateFormat extends DateFormat {
             case 17: // 'z' - ZONE_OFFSET
             {
                 Output<TimeType> tzTimeType = new Output<TimeType>();
-                Style style = (count < 4) ? Style.SPECIFIC_SHORT_COMMONLY_USED : Style.SPECIFIC_LONG;
+                Style style = (count < 4) ? Style.SPECIFIC_SHORT : Style.SPECIFIC_LONG;
                 TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
                 if (tz != null) {
-                    if (tzTimeType.value == TimeType.STANDARD) {
-                        tztype = TZTYPE_STD;
-                    } else if (tzTimeType.value == TimeType.DAYLIGHT) {
-                        tztype = TZTYPE_DST;
-                    }
+                    tztype = tzTimeType.value;
                     cal.setTimeZone(tz);
                     return pos.getIndex();
                 }
-                return -start;
-                    }
+                return ~start;
+            }
             case 23: // 'Z' - TIMEZONE_RFC
             {
                 Output<TimeType> tzTimeType = new Output<TimeType>();
-                Style style = (count < 4) ? Style.RFC822 : Style.LOCALIZED_GMT;
+                Style style = (count < 4) ? Style.ISO_BASIC_LOCAL_FULL : ((count == 5) ? Style.ISO_EXTENDED_FULL : Style.LOCALIZED_GMT);
                 TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
                 if (tz != null) {
-                    if (tzTimeType.value == TimeType.STANDARD) {
-                        tztype = TZTYPE_STD;
-                    } else if (tzTimeType.value == TimeType.DAYLIGHT) {
-                        tztype = TZTYPE_DST;
-                    }
+                    tztype = tzTimeType.value;
                     cal.setTimeZone(tz);
                     return pos.getIndex();
                     }
-                return -start;
+                return ~start;
                 }
             case 24: // 'v' - TIMEZONE_GENERIC
             {
@@ -2079,32 +2980,107 @@ public class SimpleDateFormat extends DateFormat {
                 Style style = (count < 4) ? Style.GENERIC_SHORT : Style.GENERIC_LONG;
                 TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
                 if (tz != null) {
-                    if (tzTimeType.value == TimeType.STANDARD) {
-                        tztype = TZTYPE_STD;
-                    } else if (tzTimeType.value == TimeType.DAYLIGHT) {
-                        tztype = TZTYPE_DST;
-                    }
+                    tztype = tzTimeType.value;
                     cal.setTimeZone(tz);
                     return pos.getIndex();
                 }
-                return -start;
+                return ~start;
             }
             case 29: // 'V' - TIMEZONE_SPECIAL
             {
                 Output<TimeType> tzTimeType = new Output<TimeType>();
-                // Note: 'v' only supports count 1 and 4
-                Style style = (count < 4) ? Style.SPECIFIC_SHORT : Style.GENERIC_LOCATION;
+                Style style = null;
+                switch (count) {
+                case 1:
+                    style = Style.ZONE_ID_SHORT;
+                    break;
+                case 2:
+                    style = Style.ZONE_ID;
+                    break;
+                case 3:
+                    style = Style.EXEMPLAR_LOCATION;
+                    break;
+                default:
+                    style = Style.GENERIC_LOCATION;
+                    break;
+                }
                 TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
                 if (tz != null) {
-                    if (tzTimeType.value == TimeType.STANDARD) {
-                        tztype = TZTYPE_STD;
-                    } else if (tzTimeType.value == TimeType.DAYLIGHT) {
-                        tztype = TZTYPE_DST;
+                    tztype = tzTimeType.value;
+                    cal.setTimeZone(tz);
+                    return pos.getIndex();
                 }
+                return ~start;
+            }
+            case 31: // 'O' - TIMEZONE_LOCALIZED_GMT_OFFSET
+            {
+                Output<TimeType> tzTimeType = new Output<TimeType>();
+                Style style = (count < 4) ? Style.LOCALIZED_GMT_SHORT : Style.LOCALIZED_GMT;
+                TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
+                if (tz != null) {
+                    tztype = tzTimeType.value;
                     cal.setTimeZone(tz);
                     return pos.getIndex();
                 }
-                return -start;
+                return ~start;
+            }
+            case 32: // 'X' - TIMEZONE_ISO
+            {
+                Output<TimeType> tzTimeType = new Output<TimeType>();
+                Style style;
+                switch (count) {
+                case 1:
+                    style = Style.ISO_BASIC_SHORT;
+                    break;
+                case 2:
+                    style = Style.ISO_BASIC_FIXED;
+                    break;
+                case 3:
+                    style = Style.ISO_EXTENDED_FIXED;
+                    break;
+                case 4:
+                    style = Style.ISO_BASIC_FULL;
+                    break;
+                default: // count >= 5
+                    style = Style.ISO_EXTENDED_FULL;
+                    break;
+                }
+                TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
+                if (tz != null) {
+                    tztype = tzTimeType.value;
+                    cal.setTimeZone(tz);
+                    return pos.getIndex();
+                }
+                return ~start;
+            }
+            case 33: // 'x' - TIMEZONE_ISO_LOCAL
+            {
+                Output<TimeType> tzTimeType = new Output<TimeType>();
+                Style style;
+                switch (count) {
+                case 1:
+                    style = Style.ISO_BASIC_LOCAL_SHORT;
+                    break;
+                case 2:
+                    style = Style.ISO_BASIC_LOCAL_FIXED;
+                    break;
+                case 3:
+                    style = Style.ISO_EXTENDED_LOCAL_FIXED;
+                    break;
+                case 4:
+                    style = Style.ISO_BASIC_LOCAL_FULL;
+                    break;
+                default: // count >= 5
+                    style = Style.ISO_EXTENDED_LOCAL_FULL;
+                    break;
+                }
+                TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
+                if (tz != null) {
+                    tztype = tzTimeType.value;
+                    cal.setTimeZone(tz);
+                    return pos.getIndex();
+                }
+                return ~start;
             }
             case 27: // 'Q' - QUARTER
                 if (count <= 2) { // i.e., Q or QQ.
@@ -2158,7 +3134,6 @@ public class SimpleDateFormat extends DateFormat {
                 // case 12: // 'w' - WEEK_OF_YEAR
                 // case 13: // 'W' - WEEK_OF_MONTH
                 // case 16: // 'K' - HOUR (0..11)
-                // case 18: // 'Y' - YEAR_WOY
                 // case 19: // 'e' - DOW_LOCAL
                 // case 20: // 'u' - EXTENDED_YEAR
                 // case 21: // 'g' - JULIAN_DAY
@@ -2175,7 +3150,7 @@ public class SimpleDateFormat extends DateFormat {
                     cal.set(field, number.intValue());
                     return pos.getIndex();
                 }
-                return -start;
+                return ~start;
             }
     }
 
@@ -2232,7 +3207,7 @@ public class SimpleDateFormat extends DateFormat {
                     nDigits--;
                 }
                 pos.setIndex(oldPos + maxDigits);
-                number = new Integer((int)val);
+                number = Integer.valueOf((int)val);
             }
         }
         return number;
@@ -2347,19 +3322,17 @@ public class SimpleDateFormat extends DateFormat {
      * 
      * @return the time zone formatter which this date/time
      * formatter uses.
-     * @internal ICU 4.8 technology preview
-     * @deprecated This API might change or be removed in a future release.
+     * @stable ICU 49
      */
     public TimeZoneFormat getTimeZoneFormat() {
         return tzFormat().freeze();
     }
 
     /**
-     * {@icu} Allows you to set the time zoen formatter.
+     * {@icu} Allows you to set the time zone formatter.
      * 
      * @param tzfmt the new time zone formatter
-     * @internal ICU 4.8 technology preview
-     * @deprecated This API might change or be removed in a future release.
+     * @stable ICU 49
      */
     public void setTimeZoneFormat(TimeZoneFormat tzfmt) {
         if (tzfmt.isFrozen()) {
@@ -2371,6 +3344,34 @@ public class SimpleDateFormat extends DateFormat {
         }
     }
 
+    /**
+     * {@icu} Set a particular DisplayContext value in the formatter,
+     * such as CAPITALIZATION_FOR_STANDALONE. 
+     * 
+     * @param context The DisplayContext value to set. 
+     * @draft ICU 51
+     * @provisional This API might change or be removed in a future release.
+     */
+    public void setContext(DisplayContext context) {
+        if (context.type() == DisplayContext.Type.CAPITALIZATION) {
+            capitalizationSetting = context;
+        }
+    }
+
+    /**
+     * {@icu} Get the formatter's DisplayContext value for the specified DisplayContext.Type,
+     * such as CAPITALIZATION.
+     * 
+     * @param type the DisplayContext.Type whose value to return
+     * @return the current DisplayContext setting for the specified type
+     * @draft ICU 51
+     * @provisional This API might change or be removed in a future release.
+     */
+    public DisplayContext getContext(DisplayContext.Type type) {
+        return (type == DisplayContext.Type.CAPITALIZATION && capitalizationSetting != null)?
+                capitalizationSetting: DisplayContext.CAPITALIZATION_NONE;
+    }
+
     /**
      * Overrides Cloneable
      * @stable ICU 2.0
@@ -2406,6 +3407,7 @@ public class SimpleDateFormat extends DateFormat {
 
     /**
      * Override writeObject.
+     * See http://docs.oracle.com/javase/6/docs/api/java/io/ObjectOutputStream.html
      */
     private void writeObject(ObjectOutputStream stream) throws IOException{
         if (defaultCenturyStart == null) {
@@ -2415,14 +3417,17 @@ public class SimpleDateFormat extends DateFormat {
         }
         initializeTimeZoneFormat(false);
         stream.defaultWriteObject();
+        stream.writeInt(capitalizationSetting.value());
     }
 
     /**
      * Override readObject.
+     * See http://docs.oracle.com/javase/6/docs/api/java/io/ObjectInputStream.html
      */
     private void readObject(ObjectInputStream stream)
         throws IOException, ClassNotFoundException {
         stream.defaultReadObject();
+        int capitalizationSettingValue = (serialVersionOnStream > 1)? stream.readInt(): -1;
         ///CLOVER:OFF
         // don't have old serial data to test with
         if (serialVersionOnStream < 1) {
@@ -2444,6 +3449,16 @@ public class SimpleDateFormat extends DateFormat {
         }
 
         initLocalZeroPaddingNumberFormat();
+
+        capitalizationSetting = DisplayContext.CAPITALIZATION_NONE;
+        if (capitalizationSettingValue >= 0) {
+            for (DisplayContext context: DisplayContext.values()) {
+                if (context.value() == capitalizationSettingValue) {
+                    capitalizationSetting = context;
+                    break;
+                }
+            }
+        }
     }
 
     /**
@@ -2469,7 +3484,7 @@ public class SimpleDateFormat extends DateFormat {
         StringBuffer toAppendTo = new StringBuffer();
         FieldPosition pos = new FieldPosition(0);
         List<FieldPosition> attributes = new ArrayList<FieldPosition>();
-        format(cal, toAppendTo, pos, attributes);
+        format(cal, capitalizationSetting, toAppendTo, pos, attributes);
 
         AttributedString as = new AttributedString(toAppendTo.toString());
 
@@ -2697,11 +3712,11 @@ public class SimpleDateFormat extends DateFormat {
             } else {
                 PatternItem item = (PatternItem)items[i];
                 if (useFastFormat) {
-                    subFormat(appendTo, item.type, item.length, appendTo.length(), pos,
-                              fromCalendar);
+                    subFormat(appendTo, item.type, item.length, appendTo.length(),
+                              i, capitalizationSetting, pos, fromCalendar);
                 } else {
-                    appendTo.append(subFormat(item.type, item.length, appendTo.length(), pos,
-                                              formatData, fromCalendar));
+                    appendTo.append(subFormat(item.type, item.length, appendTo.length(),
+                                              i, capitalizationSetting, pos, fromCalendar));
                 }
             }
         }
@@ -2715,10 +3730,11 @@ public class SimpleDateFormat extends DateFormat {
             } else {
                 PatternItem item = (PatternItem)items[i];
                 if (useFastFormat) {
-                    subFormat(appendTo, item.type, item.length, appendTo.length(), pos, toCalendar);
+                    subFormat(appendTo, item.type, item.length, appendTo.length(),
+                              i, capitalizationSetting, pos, toCalendar);
                 } else {
-                    appendTo.append(subFormat(item.type, item.length, appendTo.length(), pos,
-                                              formatData, toCalendar));
+                    appendTo.append(subFormat(item.type, item.length, appendTo.length(),
+                                              i, capitalizationSetting, pos, toCalendar));
                 }
             }
         }
@@ -2816,7 +3832,7 @@ public class SimpleDateFormat extends DateFormat {
     protected NumberFormat getNumberFormat(char ch) {
 
        Character ovrField;
-       ovrField = new Character(ch);
+       ovrField = Character.valueOf(ch);
        if (overrideMap != null && overrideMap.containsKey(ovrField)) {
            String nsName = overrideMap.get(ovrField).toString();
            NumberFormat nf = numberFormatters.get(nsName);
@@ -2862,7 +3878,7 @@ public class SimpleDateFormat extends DateFormat {
                fullOverride = true;
             } else { // Field specific override string such as "y=hebrew"
                nsName = currentString.substring(equalSignPosition+1);
-               ovrField = new Character(currentString.charAt(0));
+               ovrField = Character.valueOf(currentString.charAt(0));
                overrideMap.put(ovrField,nsName);
                fullOverride = false;
             }