12ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* GENERATED SOURCE. DO NOT MODIFY. */
2f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// © 2016 and later: Unicode, Inc. and others.
3f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License
42ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*
52ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *******************************************************************************
61c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Copyright (C) 1996-2016, International Business Machines Corporation and
72ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * others. All Rights Reserved.
82ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *******************************************************************************
92ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */
102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpackage android.icu.text;
122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.io.IOException;
142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.io.ObjectInputStream;
152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.io.ObjectOutputStream;
162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.text.AttributedCharacterIterator;
172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.text.AttributedString;
182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.text.FieldPosition;
192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.text.Format;
202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.text.ParsePosition;
212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.ArrayList;
222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Date;
232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.HashMap;
242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.List;
252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Locale;
262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.MissingResourceException;
272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.UUID;
282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.DateNumberFormat;
301c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubertimport android.icu.impl.DayPeriodRules;
312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.ICUCache;
32f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubertimport android.icu.impl.ICUData;
33f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubertimport android.icu.impl.ICUResourceBundle;
342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.PatternProps;
352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.SimpleCache;
361c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubertimport android.icu.impl.SimpleFormatterImpl;
372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.lang.UCharacter;
382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.text.TimeZoneFormat.Style;
392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.text.TimeZoneFormat.TimeType;
402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.BasicTimeZone;
412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.Calendar;
422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.HebrewCalendar;
432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.Output;
442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.TimeZone;
452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.TimeZoneTransition;
462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.ULocale;
472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.ULocale.Category;
48f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubertimport android.icu.util.UResourceBundle;
49f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/**
531537b2f39245c07b00aa78c3600f7aebcb172490Neil Fuller * <strong>[icu enhancement]</strong> ICU's replacement for {@link java.text.SimpleDateFormat}.&nbsp;Methods, fields, and other functionality specific to ICU are labeled '<strong>[icu]</strong>'.
542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p><code>SimpleDateFormat</code> is a concrete class for formatting and
562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * parsing dates in a locale-sensitive manner. It allows for formatting
5708ae9f2909b2ec37f755dac4372553437e9d7cf6Paul Duffin * (date -&gt; text), parsing (text -&gt; date), and normalization.
582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>
602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <code>SimpleDateFormat</code> allows you to start by choosing
612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * any user-defined patterns for date-time formatting. However, you
622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * are encouraged to create a date-time formatter with either
632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <code>getTimeInstance</code>, <code>getDateInstance</code>, or
642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <code>getDateTimeInstance</code> in <code>DateFormat</code>. Each
652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * of these class methods can return a date/time formatter initialized
662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * with a default format pattern. You may modify the format pattern
672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * using the <code>applyPattern</code> methods as desired.
682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For more information on using these methods, see
692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@link DateFormat}.
702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p><strong>Date and Time Patterns:</strong></p>
722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>Date and time formats are specified by <em>date and time pattern</em> strings.
742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Within date and time pattern strings, all unquoted ASCII letters [A-Za-z] are reserved
752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * as pattern letters representing calendar fields. <code>SimpleDateFormat</code> supports
762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the date and time formatting algorithm and pattern letters defined by <a href="http://www.unicode.org/reports/tr35/">UTS#35
772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Unicode Locale Data Markup Language (LDML)</a>. The following pattern letters are
782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * currently available (note that the actual values depend on CLDR and may change from the
792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * examples shown here):</p>
802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <blockquote>
812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <table border="1">
822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <th>Field</th>
842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <th style="text-align: center">Sym.</th>
852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <th style="text-align: center">No.</th>
862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <th>Example</th>
872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <th>Description</th>
882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <th rowspan="3">era</th>
912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center" rowspan="3">G</td>
922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..3</td>
932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>AD</td>
941c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert *         <td rowspan="3">Era - Replaced with the Era string for the current date. One to three letters for the
952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         abbreviated form, four letters for the long (wide) form, five for the narrow form.</td>
962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">4</td>
992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Anno Domini</td>
1002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
1012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
1022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">5</td>
1032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>A</td>
1042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
1052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
1062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <th rowspan="6">year</th>
1072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">y</td>
1082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..n</td>
1092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>1996</td>
1102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Year. Normally the length specifies the padding, but for two letters it also specifies the maximum
11108ae9f2909b2ec37f755dac4372553437e9d7cf6Paul Duffin *         length. Example:<div style="text-align: center">
1122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *             <center>
1132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *             <table border="1" cellpadding="2" cellspacing="0">
1142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                 <tr>
1152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <th>Year</th>
1162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <th style="text-align: right">y</th>
1172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <th style="text-align: right">yy</th>
1182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <th style="text-align: right">yyy</th>
1192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <th style="text-align: right">yyyy</th>
1202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <th style="text-align: right">yyyyy</th>
1212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                 </tr>
1222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                 <tr>
1232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td>AD 1</td>
1242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">1</td>
1252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">01</td>
1262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">001</td>
1272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">0001</td>
1282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">00001</td>
1292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                 </tr>
1302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                 <tr>
1312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td>AD 12</td>
1322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">12</td>
1332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">12</td>
1342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">012</td>
1352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">0012</td>
1362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">00012</td>
1372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                 </tr>
1382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                 <tr>
1392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td>AD 123</td>
1402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">123</td>
1412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">23</td>
1422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">123</td>
1432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">0123</td>
1442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">00123</td>
1452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                 </tr>
1462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                 <tr>
1472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td>AD 1234</td>
1482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">1234</td>
1492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">34</td>
1502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">1234</td>
1512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">1234</td>
1522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">01234</td>
1532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                 </tr>
1542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                 <tr>
1552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td>AD 12345</td>
1562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">12345</td>
1572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">45</td>
1582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">12345</td>
1592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">12345</td>
1602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                     <td style="text-align: right">12345</td>
1612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                 </tr>
1622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *             </table>
1632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *             </center></div>
1642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         </td>
1652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
1662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
1672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">Y</td>
1682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..n</td>
1692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>1997</td>
1702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Year (in "Week of Year" based calendars). Normally the length specifies the padding,
1712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         but for two letters it also specifies the maximum length. This year designation is used in ISO
1722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         year-week calendar as defined by ISO 8601, but can be used in non-Gregorian based calendar systems
1732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         where week date processing is desired. May not always be the same value as calendar year.</td>
1742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
1752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
1762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">u</td>
1772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..n</td>
1782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>4601</td>
1792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Extended year. This is a single number designating the year of this calendar system, encompassing
1802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         all supra-year fields. For example, for the Julian calendar system, year numbers are positive, with an
1812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         era of BCE or CE. An extended year value for the Julian calendar system assigns positive values to CE
1822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         years and negative values to BCE years, with 1 BCE being year 0.</td>
1832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
1842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
1852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center" rowspan="3">U</td>
1862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..3</td>
1872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>甲子</td>
1882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td rowspan="3">Cyclic year name. Calendars such as the Chinese lunar calendar (and related calendars)
1892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         and the Hindu calendars use 60-year cycles of year names. Use one through three letters for the abbreviated
1902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         name, four for the full (wide) name, or five for the narrow name (currently the data only provides abbreviated names,
1912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         which will be used for all requested name widths). If the calendar does not provide cyclic year name data,
1922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         or if the year value to be formatted is out of the range of years for which cyclic name data is provided,
1932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         then numeric formatting is used (behaves like 'y').</td>
1942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
1952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
1962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">4</td>
1972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>(currently also 甲子)</td>
1982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
1992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">5</td>
2012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>(currently also 甲子)</td>
2022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
2032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <th rowspan="6">quarter</th>
2052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td rowspan="3" style="text-align: center">Q</td>
2062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..2</td>
2072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>02</td>
2081c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert *         <td rowspan="3">Quarter - Use one or two for the numerical quarter, three for the abbreviation, or four
2092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         for the full (wide) name (five for the narrow name is not yet supported).</td>
2102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
2112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">3</td>
2132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Q2</td>
2142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
2152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">4</td>
2172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>2nd quarter</td>
2182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
2192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td rowspan="3" style="text-align: center">q</td>
2212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..2</td>
2222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>02</td>
2231c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert *         <td rowspan="3"><b>Stand-Alone</b> Quarter - Use one or two for the numerical quarter, three for the abbreviation,
2242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         or four for the full name (five for the narrow name is not yet supported).</td>
2252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
2262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">3</td>
2282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Q2</td>
2292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
2302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">4</td>
2322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>2nd quarter</td>
2332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
2342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <th rowspan="8">month</th>
2362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td rowspan="4" style="text-align: center">M</td>
2372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..2</td>
2382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>09</td>
2392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td rowspan="4">Month - Use one or two for the numerical month, three for the abbreviation, four for
2402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         the full (wide) name, or five for the narrow name. With two ("MM"), the month number is zero-padded
2412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         if necessary (e.g. "08").</td>
2422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
2432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">3</td>
2452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Sep</td>
2462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
2472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">4</td>
2492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>September</td>
2502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
2512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">5</td>
2532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>S</td>
2542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
2552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td rowspan="4" style="text-align: center">L</td>
2572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..2</td>
2582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>09</td>
2591c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert *         <td rowspan="4"><b>Stand-Alone</b> Month - Use one or two for the numerical month, three for the abbreviation,
2602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         four for the full (wide) name, or 5 for the narrow name. With two ("LL"), the month number is zero-padded if
2612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         necessary (e.g. "08").</td>
2622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
2632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">3</td>
2652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Sep</td>
2662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
2672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">4</td>
2692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>September</td>
2702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
2712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">5</td>
2732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>S</td>
2742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
2752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <th rowspan="2">week</th>
2772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">w</td>
2782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..2</td>
2792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>27</td>
2802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Week of Year. Use "w" to show the minimum number of digits, or "ww" to always show two digits
2812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         (zero-padding if necessary, e.g. "08").</td>
2822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
2832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">W</td>
2852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1</td>
2862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>3</td>
2872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Week of Month</td>
2882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
2892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <th rowspan="4">day</th>
2912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">d</td>
2922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..2</td>
2932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>1</td>
2942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Date - Day of the month. Use "d" to show the minimum number of digits, or "dd" to always show
2952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         two digits (zero-padding if necessary, e.g. "08").</td>
2962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
2972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
2982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">D</td>
2992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..3</td>
3002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>345</td>
3012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Day of year</td>
3022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
3032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
3042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">F</td>
3052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1</td>
3062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>2</td>
3072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Day of Week in Month. The example is for the 2nd Wed in July</td>
3082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
3092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
3102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">g</td>
3112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..n</td>
3122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>2451334</td>
3132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Modified Julian day. This is different from the conventional Julian day number in two regards.
3142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         First, it demarcates days at local zone midnight, rather than noon GMT. Second, it is a local number;
3151c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert *         that is, it depends on the local time zone. It can be thought of as a single number that encompasses
3162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         all the date-related fields.</td>
3172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
3182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
3192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <th rowspan="14">week<br>
3202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         day</th>
3212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td rowspan="4" style="text-align: center">E</td>
3222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..3</td>
3232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Tue</td>
3241c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert *         <td rowspan="4">Day of week - Use one through three letters for the short day, four for the full (wide) name,
3252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         five for the narrow name, or six for the short name.</td>
3262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
3272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
3282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">4</td>
3292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Tuesday</td>
3302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
3312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
3322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">5</td>
3332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>T</td>
3342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
3352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
3362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">6</td>
3372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Tu</td>
3382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
3392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
3402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td rowspan="5" style="text-align: center">e</td>
3412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..2</td>
3422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>2</td>
3432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td rowspan="5">Local day of week. Same as E except adds a numeric value that will depend on the local
3442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         starting day of the week, using one or two letters. For this example, Monday is the first day of the week.</td>
3452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
3462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
3472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">3</td>
3482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Tue</td>
3492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
3502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
3512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">4</td>
3522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Tuesday</td>
3532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
3542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
3552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">5</td>
3562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>T</td>
3572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
3582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
3592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">6</td>
3602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Tu</td>
3612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
3622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
3632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td rowspan="5" style="text-align: center">c</td>
3642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1</td>
3652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>2</td>
3662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td rowspan="5"><b>Stand-Alone</b> local day of week - Use one letter for the local numeric value (same
3672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         as 'e'), three for the short day, four for the full (wide) name, five for the narrow name, or six for
3682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         the short name.</td>
3692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
3702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
3712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">3</td>
3722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Tue</td>
3732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
3742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
3752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">4</td>
3762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Tuesday</td>
3772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
3782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
3792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">5</td>
3802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>T</td>
3812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
3822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
3832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">6</td>
3842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Tu</td>
3852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
3862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
3872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <th>period</th>
3882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">a</td>
3892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1</td>
3902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>AM</td>
3912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>AM or PM</td>
3922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
3932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
3942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <th rowspan="4">hour</th>
3952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">h</td>
3962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..2</td>
3972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>11</td>
3982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Hour [1-12]. When used in skeleton data or in a skeleton passed in an API for flexible data pattern
3992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         generation, it should match the 12-hour-cycle format preferred by the locale (h or K); it should not match
4002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         a 24-hour-cycle format (H or k). Use hh for zero padding.</td>
4012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
4022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
4032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">H</td>
4042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..2</td>
4052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>13</td>
4062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Hour [0-23]. When used in skeleton data or in a skeleton passed in an API for flexible data pattern
4072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         generation, it should match the 24-hour-cycle format preferred by the locale (H or k); it should not match a
4082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         12-hour-cycle format (h or K). Use HH for zero padding.</td>
4092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
4102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
4112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">K</td>
4122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..2</td>
4132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>0</td>
4142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Hour [0-11]. When used in a skeleton, only matches K or h, see above. Use KK for zero padding.</td>
4152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
4162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
4172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">k</td>
4182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..2</td>
4192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>24</td>
4202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Hour [1-24]. When used in a skeleton, only matches k or H, see above. Use kk for zero padding.</td>
4212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
4222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
4232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <th>minute</th>
4242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">m</td>
4252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..2</td>
4262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>59</td>
4272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Minute. Use "m" to show the minimum number of digits, or "mm" to always show two digits
4282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         (zero-padding if necessary, e.g. "08")..</td>
4292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
4302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
4312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <th rowspan="3">second</th>
4322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">s</td>
4332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..2</td>
4342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>12</td>
4352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Second. Use "s" to show the minimum number of digits, or "ss" to always show two digits
4362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         (zero-padding if necessary, e.g. "08").</td>
4372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
4382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
4392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">S</td>
4402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..n</td>
4412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>3450</td>
4422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Fractional Second - truncates (like other time fields) to the count of letters when formatting. Appends zeros if more than 3 letters specified. Truncates at three significant digits when parsing.
4432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         (example shows display using pattern SSSS for seconds value 12.34567)</td>
4442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
4452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
4462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">A</td>
4472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..n</td>
4482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>69540000</td>
4492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Milliseconds in day. This field behaves <i>exactly</i> like a composite of all time-related fields,
4502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         not including the zone fields. As such, it also reflects discontinuities of those fields on DST transition
4512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         days. On a day of DST onset, it will jump forward. On a day of DST cessation, it will jump backward. This
4522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         reflects the fact that is must be combined with the offset field to obtain a unique local time value.</td>
4532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
4542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
4552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <th rowspan="23">zone</th>
4562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td rowspan="2" style="text-align: center">z</td>
4572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..3</td>
4582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>PDT</td>
4592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>short specific non-location format</i>.
4602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         Where that is unavailable, falls back to the <i>short localized GMT format</i> ("O").</td>
4612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
4622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
4632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">4</td>
4642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Pacific Daylight Time</td>
4652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>long specific non-location format</i>.
4662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         Where that is unavailable, falls back to the <i>long localized GMT format</i> ("OOOO").</td>
4672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
4682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
4692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td rowspan="3" style="text-align: center">Z</td>
4702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1..3</td>
4712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>-0800</td>
4722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>ISO8601 basic format</i> with hours, minutes and optional seconds fields.
4732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         The format is equivalent to RFC 822 zone format (when optional seconds field is absent).
4742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         This is equivalent to the "xxxx" specifier.</td>
4752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
4762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
4772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">4</td>
4782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>GMT-8:00</td>
4792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>long localized GMT format</i>.
4802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         This is equivalent to the "OOOO" specifier.</td>
4812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
4822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
4832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">5</td>
4842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>-08:00<br>
4852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         -07:52:58</td>
4862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>ISO8601 extended format</i> with hours, minutes and optional seconds fields.
4872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         The ISO8601 UTC indicator "Z" is used when local time offset is 0.
4882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         This is equivalent to the "XXXXX" specifier.</td>
4892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
4902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
4912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td rowspan="2" style="text-align: center">O</td>
4922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1</td>
4932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>GMT-8</td>
4942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>short localized GMT format</i>.</td>
4952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
4962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
4972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">4</td>
4982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>GMT-08:00</td>
4992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>long localized GMT format</i>.</td>
5002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
5012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
5022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td rowspan="2" style="text-align: center">v</td>
5032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1</td>
5042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>PT</td>
5052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>short generic non-location format</i>.
5062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         Where that is unavailable, falls back to the <i>generic location format</i> ("VVVV"),
5072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         then the <i>short localized GMT format</i> as the final fallback.</td>
5082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
5092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
5102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">4</td>
5112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Pacific Time</td>
5122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>long generic non-location format</i>.
5132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         Where that is unavailable, falls back to <i>generic location format</i> ("VVVV").
5142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
5152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
5162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td rowspan="4" style="text-align: center">V</td>
5172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1</td>
5182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>uslax</td>
5192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The short time zone ID.
5202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         Where that is unavailable, the special short time zone ID <i>unk</i> (Unknown Zone) is used.<br>
5212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <i><b>Note</b>: This specifier was originally used for a variant of the short specific non-location format,
5222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         but it was deprecated in the later version of the LDML specification. In CLDR 23/ICU 51, the definition of
5232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         the specifier was changed to designate a short time zone ID.</i></td>
5242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
5252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
5262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">2</td>
5272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>America/Los_Angeles</td>
5282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The long time zone ID.</td>
5292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
5302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
5312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">3</td>
5322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Los Angeles</td>
5332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The exemplar city (location) for the time zone.
5342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         Where that is unavailable, the localized exemplar city name for the special zone <i>Etc/Unknown</i> is used
5352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         as the fallback (for example, "Unknown City"). </td>
5362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
5372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
5382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">4</td>
5392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>Los Angeles Time</td>
5402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>generic location format</i>.
5412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         Where that is unavailable, falls back to the <i>long localized GMT format</i> ("OOOO";
5422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         Note: Fallback is only necessary with a GMT-style Time Zone ID, like Etc/GMT-830.)<br>
5431c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert *         This is especially useful when presenting possible timezone choices for user selection,
5442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         since the naming is more uniform than the "v" format.</td>
5452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
5462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
5472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td rowspan="5" style="text-align: center">X</td>
5482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1</td>
5492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>-08<br>
5502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         +0530<br>
5512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         Z</td>
5522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>ISO8601 basic format</i> with hours field and optional minutes field.
5532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         The ISO8601 UTC indicator "Z" is used when local time offset is 0.</td>
5542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
5552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
5562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">2</td>
5572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>-0800<br>
5582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         Z</td>
5592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>ISO8601 basic format</i> with hours and minutes fields.
5602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         The ISO8601 UTC indicator "Z" is used when local time offset is 0.</td>
5612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
5622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
5632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">3</td>
5642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>-08:00<br>
5652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         Z</td>
5662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>ISO8601 extended format</i> with hours and minutes fields.
5672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         The ISO8601 UTC indicator "Z" is used when local time offset is 0.</td>
5682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
5692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
5702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">4</td>
5712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>-0800<br>
5722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         -075258<br>
5732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         Z</td>
5742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>ISO8601 basic format</i> with hours, minutes and optional seconds fields.
5752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         (Note: The seconds field is not supported by the ISO8601 specification.)
5762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         The ISO8601 UTC indicator "Z" is used when local time offset is 0.</td>
5772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
5782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
5792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">5</td>
5802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>-08:00<br>
5812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         -07:52:58<br>
5822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         Z</td>
5832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>ISO8601 extended format</i> with hours, minutes and optional seconds fields.
5842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         (Note: The seconds field is not supported by the ISO8601 specification.)
5852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         The ISO8601 UTC indicator "Z" is used when local time offset is 0.</td>
5862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
5872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
5882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td rowspan="5" style="text-align: center">x</td>
5892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">1</td>
5902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>-08<br>
5912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         +0530</td>
5922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>ISO8601 basic format</i> with hours field and optional minutes field.</td>
5932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
5942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
5952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">2</td>
5962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>-0800</td>
5972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>ISO8601 basic format</i> with hours and minutes fields.</td>
5982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
5992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
6002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">3</td>
6012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>-08:00</td>
6022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>ISO8601 extended format</i> with hours and minutes fields.</td>
6032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
6042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
6052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">4</td>
6062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>-0800<br>
6072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         -075258</td>
6082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>ISO8601 basic format</i> with hours, minutes and optional seconds fields.
6092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         (Note: The seconds field is not supported by the ISO8601 specification.)</td>
6102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
6112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     <tr>
6122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td style="text-align: center">5</td>
6132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>-08:00<br>
6142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         -07:52:58</td>
6152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         <td>The <i>ISO8601 extended format</i> with hours, minutes and optional seconds fields.
6162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *         (Note: The seconds field is not supported by the ISO8601 specification.)</td>
6172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     </tr>
6182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </table>
6191c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert *
6202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </blockquote>
6212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>
6222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Any characters in the pattern that are not in the ranges of ['a'..'z']
6232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and ['A'..'Z'] will be treated as quoted text. For instance, characters
6242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * like ':', '.', ' ', '#' and '@' will appear in the resulting time text
6252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * even they are not embraced within single quotes.
6262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>
6272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * A pattern containing any invalid pattern letter will result in a thrown
6282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * exception during formatting or parsing.
6292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
6302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>
6312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <strong>Examples Using the US Locale:</strong>
6322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <blockquote>
6332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <pre>
6342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Format Pattern                         Result
6352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * --------------                         -------
63608ae9f2909b2ec37f755dac4372553437e9d7cf6Paul Duffin * "yyyy.MM.dd G 'at' HH:mm:ss vvvv" -&gt;&gt;  1996.07.10 AD at 15:08:56 Pacific Time
63708ae9f2909b2ec37f755dac4372553437e9d7cf6Paul Duffin * "EEE, MMM d, ''yy"                -&gt;&gt;  Wed, July 10, '96
63808ae9f2909b2ec37f755dac4372553437e9d7cf6Paul Duffin * "h:mm a"                          -&gt;&gt;  12:08 PM
63908ae9f2909b2ec37f755dac4372553437e9d7cf6Paul Duffin * "hh 'o''clock' a, zzzz"           -&gt;&gt;  12 o'clock PM, Pacific Daylight Time
64008ae9f2909b2ec37f755dac4372553437e9d7cf6Paul Duffin * "K:mm a, vvv"                     -&gt;&gt;  0:00 PM, PT
64108ae9f2909b2ec37f755dac4372553437e9d7cf6Paul Duffin * "yyyyy.MMMMM.dd GGG hh:mm aaa"    -&gt;&gt;  01996.July.10 AD 12:08 PM
6422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </pre>
6432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </blockquote>
6442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <strong>Code Sample:</strong>
6452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <blockquote>
6462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <pre>
6472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, "PST");
6482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2*60*60*1000);
6492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*60*60*1000);
6502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <br>
6512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * // Format the current time.
6522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * SimpleDateFormat formatter
6532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     = new SimpleDateFormat ("yyyy.MM.dd G 'at' hh:mm:ss a zzz");
6542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Date currentTime_1 = new Date();
6552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * String dateString = formatter.format(currentTime_1);
6562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <br>
6572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * // Parse the previous string back into a Date.
6582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * ParsePosition pos = new ParsePosition(0);
6592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Date currentTime_2 = formatter.parse(dateString, pos);
6602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </pre>
6612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </blockquote>
6622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * In the example, the time value <code>currentTime_2</code> obtained from
6632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * parsing will be equal to <code>currentTime_1</code>. However, they may not be
6642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * equal if the am/pm marker 'a' is left out from the format pattern while
6652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the "hour in am/pm" pattern symbol is used. This information loss can
6662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * happen when formatting the time in PM.
6672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
6682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>When parsing a date string using the abbreviated year pattern ("yy"),
6692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * SimpleDateFormat must interpret the abbreviated year
6702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * relative to some century.  It does this by adjusting dates to be
6712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * within 80 years before and 20 years after the time the SimpleDateFormat
6722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * instance is created. For example, using a pattern of "MM/dd/yy" and a
6732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * SimpleDateFormat instance created on Jan 1, 1997,  the string
6742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * "01/11/12" would be interpreted as Jan 11, 2012 while the string "05/04/64"
6752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * would be interpreted as May 4, 1964.
6762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * During parsing, only strings consisting of exactly two digits, as defined by
6772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@link android.icu.lang.UCharacter#isDigit(int)}, will be parsed into the default
6782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * century.
6792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Any other numeric string, such as a one digit string, a three or more digit
6802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * string, or a two digit string that isn't all digits (for example, "-1"), is
6812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * interpreted literally.  So "01/02/3" or "01/02/003" are parsed, using the
6822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * same pattern, as Jan 2, 3 AD.  Likewise, "01/02/-3" is parsed as Jan 2, 4 BC.
6832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
6842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>If the year pattern does not have exactly two 'y' characters, the year is
6852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * interpreted literally, regardless of the number of digits.  So using the
6862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * pattern "MM/dd/yyyy", "01/11/12" parses to Jan 11, 12 A.D.
6872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
6882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>When numeric fields abut one another directly, with no intervening delimiter
6892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * characters, they constitute a run of abutting numeric fields.  Such runs are
6902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * parsed specially.  For example, the format "HHmmss" parses the input text
6912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * "123456" to 12:34:56, parses the input text "12345" to 1:23:45, and fails to
6922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * parse "1234".  In other words, the leftmost field of the run is flexible,
6932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * while the others keep a fixed width.  If the parse fails anywhere in the run,
6942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * then the leftmost field is shortened by one character, and the entire run is
6952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * parsed again. This is repeated until either the parse succeeds or the
6962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * leftmost field is one character in length.  If the parse still fails at that
6972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * point, the parse of the run fails.
6982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
6992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>For time zones that have no names, use strings GMT+hours:minutes or
7002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * GMT-hours:minutes.
7012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
7022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <p>The calendar defines what is the first day of the week, the first week
7032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * of the year, whether hours are zero based or not (0 vs 12 or 24), and the
7042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * time zone. There is one common decimal format to handle all the numbers;
7052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the digit count is handled programmatically according to the pattern.
7062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
70708ae9f2909b2ec37f755dac4372553437e9d7cf6Paul Duffin * <h3>Synchronization</h3>
7082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
7092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Date formats are not synchronized. It is recommended to create separate
7102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * format instances for each thread. If multiple threads access a format
7112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * concurrently, it must be synchronized externally.
7122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
7132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @see          android.icu.util.Calendar
7142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @see          android.icu.util.GregorianCalendar
7152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @see          android.icu.util.TimeZone
7162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @see          DateFormat
7172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @see          DateFormatSymbols
7182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @see          DecimalFormat
7192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @see          TimeZoneFormat
7202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @author       Mark Davis, Chen-Lieh Huang, Alan Liu
7212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */
7222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpublic class SimpleDateFormat extends DateFormat {
7232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // the official serial version ID which says cryptically
7252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // which version we're compatible with
7262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final long serialVersionUID = 4774881970558875024L;
7272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // the internal serial version which says which version was written
7292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // - 0 (default) for version up to JDK 1.1.3
7302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // - 1 for version from JDK 1.1.4, which includes a new field
7312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // - 2 we write additional int for capitalizationSetting
7322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final int currentSerialVersion = 2;
7332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static boolean DelayedHebrewMonthCheck = false;
7352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
7372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * From calendar field to its level.
7382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Used to order calendar field.
7392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * For example, calendar fields can be defined in the following order:
7402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * year >  month > date > am-pm > hour >  minute
7412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * YEAR --> 10, MONTH -->20, DATE --> 30;
7422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * AM_PM -->40, HOUR --> 50, MINUTE -->60
7432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
7442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int[] CALENDAR_FIELD_TO_LEVEL =
7452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
7462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*GyM*/ 0, 10, 20,
7472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*wW*/ 20, 30,
7482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*dDEF*/ 30, 20, 30, 30,
7492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*ahHm*/ 40, 50, 50, 60,
7502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*sS*/ 70, 80,
7512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*z?Y*/ 0, 0, 10,
7522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*eug*/ 30, 10, 0,
7532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*A?*/ 40, 0, 0
7542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
7552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
7572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * From calendar field letter to its level.
7582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Used to order calendar field.
7592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * For example, calendar fields can be defined in the following order:
7602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * year >  month > date > am-pm > hour >  minute
7612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 'y' --> 10, 'M' -->20, 'd' --> 30; 'a' -->40, 'h' --> 50, 'm' -->60
7622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
7632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int[] PATTERN_CHAR_TO_LEVEL =
7642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
7652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
7662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //
7672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
7682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //       !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /
7692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
7702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
7712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
7722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //   @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
7732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        -1, 40, -1, -1, 20, 30, 30,  0, 50, -1, -1, 50, 20, 20, -1,  0,
7742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //   P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _
7752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        -1, 20, -1, 80, -1, 10,  0, 30,  0, 10,  0, -1, -1, -1, -1, -1,
7762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //   `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
7772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        -1, 40, -1, 30, 30, 30, -1,  0, 50, -1, -1, 50, -1, 60, -1, -1,
7782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //   p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~
7792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        -1, 20, 10, 70, -1, 10,  0, 20,  0, 10,  0, -1, -1, -1, -1, -1,
7802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
7812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
7832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Map calendar field letter into calendar field level.
7842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
7852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static int getLevelFromChar(char ch) {
7862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return ch < PATTERN_CHAR_TO_LEVEL.length ? PATTERN_CHAR_TO_LEVEL[ch & 0xff] : -1;
7872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
7882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final boolean[] PATTERN_CHAR_IS_SYNTAX =
7902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
7912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //
7922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        false, false, false, false, false, false, false, false,
7932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //
7942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        false, false, false, false, false, false, false, false,
7952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //
7962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        false, false, false, false, false, false, false, false,
7972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //
7982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        false, false, false, false, false, false, false, false,
7992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //         !      "      #      $      %      &      '
8002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        false, false, false, false, false, false, false, false,
8012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //  (      )      *      +      ,      -      .      /
8022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        false, false, false, false, false, false, false, false,
8032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //  0      1      2      3      4      5      6      7
8042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        false, false, false, false, false, false, false, false,
8052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //  8      9      :      ;      <      =      >      ?
8062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        false, false, false, false, false, false, false, false,
8072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //  @      A      B      C      D      E      F      G
8082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        false,  true,  true,  true,  true,  true,  true,  true,
8092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //  H      I      J      K      L      M      N      O
8102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         true,  true,  true,  true,  true,  true,  true,  true,
8112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //  P      Q      R      S      T      U      V      W
8122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         true,  true,  true,  true,  true,  true,  true,  true,
8132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //  X      Y      Z      [      \      ]      ^      _
8142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         true,  true,  true, false, false, false, false, false,
8152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //  `      a      b      c      d      e      f      g
8162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        false,  true,  true,  true,  true,  true,  true,  true,
8172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //  h      i      j      k      l      m      n      o
8182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         true,  true,  true,  true,  true,  true,  true,  true,
8192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //  p      q      r      s      t      u      v      w
8202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         true,  true,  true,  true,  true,  true,  true,  true,
8212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //  x      y      z      {      |      }      ~
8222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         true,  true,  true, false, false, false, false, false,
8232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
8242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Tell if a character can be used to define a field in a format string.
8272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static boolean isSyntaxChar(char ch) {
8292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return ch < PATTERN_CHAR_IS_SYNTAX.length ? PATTERN_CHAR_IS_SYNTAX[ch & 0xff] : false;
8302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
8312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // When calendar uses hebr numbering (i.e. he@calendar=hebrew),
8332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // offset the years within the current millenium down to 1-999
8342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int HEBREW_CAL_CUR_MILLENIUM_START_YEAR = 5000;
8352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int HEBREW_CAL_CUR_MILLENIUM_END_YEAR = 6000;
8362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The version of the serialized data on the stream.  Possible values:
8392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <ul>
8402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li><b>0</b> or not present on stream: JDK 1.1.3.  This version
8412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * has no <code>defaultCenturyStart</code> on stream.
8422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li><b>1</b> JDK 1.1.4 or later.  This version adds
8432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>defaultCenturyStart</code>.
8442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <li><b>2</b> This version writes an additional int for
8452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>capitalizationSetting</code>.
8462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * </ul>
8472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * When streaming out this class, the most recent format
8482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * and the highest allowable <code>serialVersionOnStream</code>
8492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * is written.
8502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @serial
8512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int serialVersionOnStream = currentSerialVersion;
8532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The pattern string of this formatter.  This is always a non-localized
8562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * pattern.  May not be null.  See class documentation for details.
8572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @serial
8582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private String pattern;
8602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The override string of this formatter.  Used to override the
8632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * numbering system for one or more fields.
8642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @serial
8652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private String override;
8672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The hash map used for number format overrides.
8702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @serial
8712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private HashMap<String, NumberFormat> numberFormatters;
8732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The hash map used for number format overrides.
8762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @serial
8772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private HashMap<Character, String> overrideMap;
8792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The symbols used by this formatter for week names, month names,
8822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * etc.  May not be null.
8832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @serial
8842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see DateFormatSymbols
8852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private DateFormatSymbols formatData;
8872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private transient ULocale locale;
8892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * We map dates with two-digit years into the century starting at
8922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>defaultCenturyStart</code>, which may be any date.  May
8932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * not be null.
8942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @serial
8952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private Date defaultCenturyStart;
8972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private transient int defaultCenturyStartYear;
8992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // defaultCenturyBase is set when an instance is created
9012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // and may be used for calculating defaultCenturyStart when needed.
9022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private transient long defaultCenturyBase;
9032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int millisPerHour = 60 * 60 * 1000;
9052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // When possessing ISO format, the ERA may be ommitted is the
9072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // year specifier is a negative number.
9082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int ISOSpecialEra = -32000;
9091c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
9102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // This prefix is designed to NEVER MATCH real text, in order to
9112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // suppress the parsing of negative numbers.  Adjust as needed (if
9122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // this becomes valid Unicode).
9132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final String SUPPRESS_NEGATIVE_PREFIX = "\uAB00";
9142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
9162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If true, this object supports fast formatting using the
9172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * subFormat variant that takes a StringBuffer.
9182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private transient boolean useFastFormat;
9202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
9222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  The time zone sub-formatter, introduced in ICU 4.8
9232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private volatile TimeZoneFormat tzFormat;
9252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
9272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * BreakIterator to use for capitalization
9282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private transient BreakIterator capitalizationBrkIter = null;
9302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9311c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert    /**
9321c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert     * DateFormat pattern contains the minute field.
9331c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert     */
9341c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert    private transient boolean hasMinute;
9351c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
9361c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert    /**
9371c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert     * DateFormat pattern contains the second field.
9381c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert     */
9391c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert    private transient boolean hasSecond;
9401c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
9412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
9422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  Capitalization setting, introduced in ICU 50
9432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  Special serialization, see writeObject & readObject below
9442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
9452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  Hoisted to DateFormat in ICU 53, get value with
9462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  getContext(DisplayContext.Type.CAPITALIZATION)
9472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // private transient DisplayContext capitalizationSetting;
9492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
9512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  Old defaultCapitalizationContext field
9522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  from ICU 49.1:
9532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //private ContextValue defaultCapitalizationContext;
9552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
9562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  Old ContextValue enum, preserved only to avoid
9572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  deserialization errs from ICU 49.1.
9582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @SuppressWarnings("unused")
9602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private enum ContextValue {
9612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        UNKNOWN,
9622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,
9632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE,
9642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        CAPITALIZATION_FOR_UI_LIST_OR_MENU,
9652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        CAPITALIZATION_FOR_STANDALONE
9662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
9672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
9692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Constructs a SimpleDateFormat using the default pattern for the default <code>FORMAT</code>
9702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * locale.  <b>Note:</b> Not all locales support SimpleDateFormat; for full
9712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * generality, use the factory methods in the DateFormat class.
9722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
9732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see DateFormat
9742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see Category#FORMAT
9752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public SimpleDateFormat() {
9772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this(getDefaultPattern(), null, null, null, null, true, null);
9782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
9792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
9812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Constructs a SimpleDateFormat using the given pattern in the default <code>FORMAT</code>
9822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * locale.  <b>Note:</b> Not all locales support SimpleDateFormat; for full
9832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * generality, use the factory methods in the DateFormat class.
9842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see Category#FORMAT
9852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public SimpleDateFormat(String pattern)
9872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
9882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this(pattern, null, null, null, null, true, null);
9892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
9902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
9922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Constructs a SimpleDateFormat using the given pattern and locale.
9932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <b>Note:</b> Not all locales support SimpleDateFormat; for full
9942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * generality, use the factory methods in the DateFormat class.
9952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public SimpleDateFormat(String pattern, Locale loc)
9972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
9982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this(pattern, null, null, null, ULocale.forLocale(loc), true, null);
9992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
10002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
10022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Constructs a SimpleDateFormat using the given pattern and locale.
10032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <b>Note:</b> Not all locales support SimpleDateFormat; for full
10042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * generality, use the factory methods in the DateFormat class.
10052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public SimpleDateFormat(String pattern, ULocale loc)
10072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
10082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this(pattern, null, null, null, loc, true, null);
10092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
10102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
10122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Constructs a SimpleDateFormat using the given pattern , override and locale.
10132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param pattern The pattern to be used
10142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param override The override string.  A numbering system override string can take one of the following forms:
10152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *     1). If just a numbering system name is specified, it applies to all numeric fields in the date format pattern.
10162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *     2). To specify an alternate numbering system on a field by field basis, use the field letters from the pattern
10172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         followed by an = sign, followed by the numbering system name.  For example, to specify that just the year
10182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         be formatted using Hebrew digits, use the override "y=hebr".  Multiple overrides can be specified in a single
10192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         string by separating them with a semi-colon. For example, the override string "m=thai;y=deva" would format using
10202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         Thai digits for the month and Devanagari digits for the year.
10212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param loc The locale to be used
10222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public SimpleDateFormat(String pattern, String override, ULocale loc)
10242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
10252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this(pattern, null, null, null, loc, false,override);
10262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
10272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
10292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Constructs a SimpleDateFormat using the given pattern and
10302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * locale-specific symbol data.
10312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Warning: uses default <code>FORMAT</code> locale for digits!
10322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public SimpleDateFormat(String pattern, DateFormatSymbols formatData)
10342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
10352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this(pattern, (DateFormatSymbols)formatData.clone(), null, null, null, true, null);
10362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
10372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
10392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @deprecated This API is ICU internal only.
104093cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller     * @hide original deprecated declaration
1041836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller     * @hide draft / provisional / internal are hidden on Android
10422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Deprecated
10442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public SimpleDateFormat(String pattern, DateFormatSymbols formatData, ULocale loc)
10452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
10462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this(pattern, (DateFormatSymbols)formatData.clone(), null, null, loc, true,null);
10472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
10482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
10502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Package-private constructor that allows a subclass to specify
10512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * whether it supports fast formatting.
10522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
10532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * TODO make this API public.
10542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    SimpleDateFormat(String pattern, DateFormatSymbols formatData, Calendar calendar, ULocale locale,
10562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                     boolean useFastFormat, String override) {
10572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this(pattern, (DateFormatSymbols)formatData.clone(), (Calendar)calendar.clone(), null, locale, useFastFormat,override);
10582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
10592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
10612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The constructor called from all other SimpleDateFormat constructors
10622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private SimpleDateFormat(String pattern, DateFormatSymbols formatData, Calendar calendar,
10642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            NumberFormat numberFormat, ULocale locale, boolean useFastFormat,String override) {
10652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.pattern = pattern;
10662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.formatData = formatData;
10672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.calendar = calendar;
10682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.numberFormat = numberFormat;
10692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.locale = locale; // time zone formatting
10702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.useFastFormat = useFastFormat;
10712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.override = override;
10722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        initialize();
10732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
10742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
10762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Creates an instance of SimpleDateFormat for the given format configuration
10772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param formatConfig the format configuration
10782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return A SimpleDateFormat instance
10792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @deprecated This API is ICU internal only.
108093cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller     * @hide original deprecated declaration
1081836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller     * @hide draft / provisional / internal are hidden on Android
10822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Deprecated
10842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static SimpleDateFormat getInstance(Calendar.FormatConfiguration formatConfig) {
10852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String ostr = formatConfig.getOverrideString();
10872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean useFast = ( ostr != null && ostr.length() > 0 );
10882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return new SimpleDateFormat(formatConfig.getPatternString(),
10902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    formatConfig.getDateFormatSymbols(),
10912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    formatConfig.getCalendar(),
10922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    null,
10932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    formatConfig.getLocale(),
10942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    useFast,
10952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    formatConfig.getOverrideString());
10962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
10972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
10992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Initialized fields
11002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
11012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void initialize() {
11022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (locale == null) {
11032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            locale = ULocale.getDefault(Category.FORMAT);
11042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
11052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (formatData == null) {
11062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            formatData = new DateFormatSymbols(locale);
11072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
11082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (calendar == null) {
11092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            calendar = Calendar.getInstance(locale);
11102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
11112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (numberFormat == null) {
11122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            NumberingSystem ns = NumberingSystem.getInstance(locale);
11132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (ns.isAlgorithmic()) {
11142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                numberFormat = NumberFormat.getInstance(locale);
11152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
11162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                String digitString = ns.getDescription();
11172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                String nsName = ns.getName();
11182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Use a NumberFormat optimized for date formatting
11192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                numberFormat = new DateNumberFormat(locale, digitString, nsName);
11202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
11212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
11222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Note: deferring calendar calculation until when we really need it.
11232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Instead, we just record time of construction for backward compatibility.
11242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        defaultCenturyBase = System.currentTimeMillis();
11252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        setLocale(calendar.getLocale(ULocale.VALID_LOCALE ), calendar.getLocale(ULocale.ACTUAL_LOCALE));
11272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        initLocalZeroPaddingNumberFormat();
11282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (override != null) {
11302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           initNumberFormatters(locale);
11312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
11321c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
11331c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        parsePattern();
11342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
11352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
11372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Private method lazily instantiate the TimeZoneFormat field
11382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param bForceUpdate when true, check if tzFormat is synchronized with
11392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the current numberFormat and update its digits if necessary. When false,
11402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * this check is skipped.
11412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
11422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private synchronized void initializeTimeZoneFormat(boolean bForceUpdate) {
11432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (bForceUpdate || tzFormat == null) {
11442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            tzFormat = TimeZoneFormat.getInstance(locale);
11452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String digits = null;
11472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (numberFormat instanceof DecimalFormat) {
11482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                DecimalFormatSymbols decsym = ((DecimalFormat) numberFormat).getDecimalFormatSymbols();
11492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                digits = new String(decsym.getDigits());
11502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (numberFormat instanceof DateNumberFormat) {
11512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                digits = new String(((DateNumberFormat)numberFormat).getDigits());
11522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
11532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (digits != null) {
11552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (!tzFormat.getGMTOffsetDigits().equals(digits)) {
11562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (tzFormat.isFrozen()) {
11572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        tzFormat = tzFormat.cloneAsThawed();
11582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
11592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    tzFormat.setGMTOffsetDigits(digits);
11602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
11612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
11622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
11632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
11642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
11662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Private method, returns non-null TimeZoneFormat.
11672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the TimeZoneFormat used by this formatter.
11682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
11692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private TimeZoneFormat tzFormat() {
11702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (tzFormat == null) {
11712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            initializeTimeZoneFormat(false);
11722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
11732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return tzFormat;
11742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
11752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // privates for the default pattern
11772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static ULocale cachedDefaultLocale = null;
11782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static String cachedDefaultPattern = null;
11792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final String FALLBACKPATTERN = "yy/MM/dd HH:mm";
11802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
11822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Returns the default date and time pattern (SHORT) for the default locale.
11832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This method is only used by the default SimpleDateFormat constructor.
11842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
11852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static synchronized String getDefaultPattern() {
11862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        ULocale defaultLocale = ULocale.getDefault(Category.FORMAT);
11872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (!defaultLocale.equals(cachedDefaultLocale)) {
11882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            cachedDefaultLocale = defaultLocale;
11892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            Calendar cal = Calendar.getInstance(cachedDefaultLocale);
1190f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
11912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            try {
1192f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                // Load the calendar data directly.
1193f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                ICUResourceBundle rb = (ICUResourceBundle) UResourceBundle.getBundleInstance(
1194f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                        ICUData.ICU_BASE_NAME, cachedDefaultLocale);
1195f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                String resourcePath = "calendar/" + cal.getType() + "/DateTimePatterns";
1196f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                ICUResourceBundle patternsRb= rb.findWithFallback(resourcePath);
1197f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
1198f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                if (patternsRb == null) {
1199f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                    patternsRb = rb.findWithFallback("calendar/gregorian/DateTimePatterns");
1200f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                }
1201f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                if (patternsRb == null || patternsRb.getSize() < 9) {
1202f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                    cachedDefaultPattern = FALLBACKPATTERN;
1203f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                } else {
1204f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                    int defaultIndex = 8;
1205f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                    if (patternsRb.getSize() >= 13) {
1206f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                        defaultIndex += (SHORT + 1);
1207f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                    }
1208f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                    String basePattern = patternsRb.getString(defaultIndex);
1209f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
1210f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                    cachedDefaultPattern = SimpleFormatterImpl.formatRawPattern(
1211f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                            basePattern, 2, 2,
1212f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                            patternsRb.getString(SHORT), patternsRb.getString(SHORT + 4));
1213f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                }
12142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } catch (MissingResourceException e) {
12152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                cachedDefaultPattern = FALLBACKPATTERN;
12162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
12172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
12182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return cachedDefaultPattern;
12192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* Define one-century window into which to disambiguate dates using
12222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * two-digit years.
12232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
12242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void parseAmbiguousDatesAsAfter(Date startDate) {
12252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        defaultCenturyStart = startDate;
12262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        calendar.setTime(startDate);
12272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        defaultCenturyStartYear = calendar.get(Calendar.YEAR);
12282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* Initialize defaultCenturyStart and defaultCenturyStartYear by base time.
12312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The default start time is 80 years before the creation time of this object.
12322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
12332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void initializeDefaultCenturyStart(long baseTime) {
12342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        defaultCenturyBase = baseTime;
12352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // clone to avoid messing up date stored in calendar object
12362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // when this method is called while parsing
12372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Calendar tmpCal = (Calendar)calendar.clone();
12382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        tmpCal.setTimeInMillis(baseTime);
12392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        tmpCal.add(Calendar.YEAR, -80);
12402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        defaultCenturyStart = tmpCal.getTime();
12412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        defaultCenturyStartYear = tmpCal.get(Calendar.YEAR);
12422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* Gets the default century start date for this object */
12452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private Date getDefaultCenturyStart() {
12462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (defaultCenturyStart == null) {
12472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // not yet initialized
12482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            initializeDefaultCenturyStart(defaultCenturyBase);
12492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
12502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return defaultCenturyStart;
12512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /* Gets the default century start year for this object */
12542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int getDefaultCenturyStartYear() {
12552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (defaultCenturyStart == null) {
12562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // not yet initialized
12572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            initializeDefaultCenturyStart(defaultCenturyBase);
12582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
12592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return defaultCenturyStartYear;
12602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
12632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Sets the 100-year period 2-digit years will be interpreted as being in
12642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * to begin on the date the user specifies.
12652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param startDate During parsing, two digit years will be placed in the range
12662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <code>startDate</code> to <code>startDate + 100 years</code>.
12672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
12682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void set2DigitYearStart(Date startDate) {
12692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        parseAmbiguousDatesAsAfter(startDate);
12702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
12732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Returns the beginning date of the 100-year period 2-digit years are interpreted
12742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * as being within.
12752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the start of the 100-year period into which two digit years are
12762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * parsed
12772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
12782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Date get2DigitYearStart() {
12792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return getDefaultCenturyStart();
12802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
12831537b2f39245c07b00aa78c3600f7aebcb172490Neil Fuller     * <strong>[icu]</strong> Set a particular DisplayContext value in the formatter,
12841c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert     * such as CAPITALIZATION_FOR_STANDALONE. Note: For getContext, see
12852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * DateFormat.
12861c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert     *
12871c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert     * @param context The DisplayContext value to set.
12882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
12892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // Here we override the DateFormat implementation in order to lazily initialize relevant items
1290f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    @Override
12912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void setContext(DisplayContext context) {
12922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        super.setContext(context);
12932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (capitalizationBrkIter == null && (context==DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
12942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              context==DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU ||
12952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              context==DisplayContext.CAPITALIZATION_FOR_STANDALONE)) {
12962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            capitalizationBrkIter = BreakIterator.getSentenceInstance(locale);
12972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
12982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
13012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Formats a date or time, which is the standard millis
13022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * since January 1, 1970, 00:00:00 GMT.
13032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>Example: using the US locale:
130408ae9f2909b2ec37f755dac4372553437e9d7cf6Paul Duffin     * "yyyy.MM.dd G 'at' HH:mm:ss zzz" -&gt;&gt; 1996.07.10 AD at 15:08:56 PDT
13052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param cal the calendar whose date-time value is to be formatted into a date-time string
13062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param toAppendTo where the new date-time text is to be appended
13072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param pos the formatting position. On input: an alignment field,
13082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * if desired. On output: the offsets of the alignment field.
13092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the formatted date-time string.
13102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see DateFormat
13112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1312f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    @Override
13132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public StringBuffer format(Calendar cal, StringBuffer toAppendTo,
13142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                               FieldPosition pos) {
13152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        TimeZone backupTZ = null;
13162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (cal != calendar && !cal.getType().equals(calendar.getType())) {
13172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Different calendar type
13182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // We use the time and time zone from the input calendar, but
13192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // do not use the input calendar for field calculation.
13202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            calendar.setTimeInMillis(cal.getTimeInMillis());
13212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            backupTZ = calendar.getTimeZone();
13222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            calendar.setTimeZone(cal.getTimeZone());
13232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            cal = calendar;
13242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
13252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        StringBuffer result = format(cal, getContext(DisplayContext.Type.CAPITALIZATION), toAppendTo, pos, null);
13262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (backupTZ != null) {
13272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Restore the original time zone
13282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            calendar.setTimeZone(backupTZ);
13292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
13302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return result;
13312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
13322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // The actual method to format date. If List attributes is not null,
13342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // then attribute information will be recorded.
13352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private StringBuffer format(Calendar cal, DisplayContext capitalizationContext,
13362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            StringBuffer toAppendTo, FieldPosition pos, List<FieldPosition> attributes) {
13372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Initialize
13382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pos.setBeginIndex(0);
13392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pos.setEndIndex(0);
13402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Careful: For best performance, minimize the number of calls
13422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // to StringBuffer.append() by consolidating appends when
13432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // possible.
13442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Object[] items = getPatternItems();
13462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = 0; i < items.length; i++) {
13472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (items[i] instanceof String) {
13482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                toAppendTo.append((String)items[i]);
13492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
13502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                PatternItem item = (PatternItem)items[i];
13512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int start = 0;
13522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (attributes != null) {
13532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Save the current length
13542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    start = toAppendTo.length();
13552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
13562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (useFastFormat) {
13572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    subFormat(toAppendTo, item.type, item.length, toAppendTo.length(),
13582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                              i, capitalizationContext, pos, cal);
13592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
13602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    toAppendTo.append(subFormat(item.type, item.length, toAppendTo.length(),
13612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                i, capitalizationContext, pos, cal));
13622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
13632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (attributes != null) {
13642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Check the sub format length
13652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int end = toAppendTo.length();
13662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (end - start > 0) {
13672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // Append the attribute to the list
13682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        DateFormat.Field attr = patternCharToDateFormatField(item.type);
13692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        FieldPosition fp = new FieldPosition(attr);
13702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        fp.setBeginIndex(start);
13712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        fp.setEndIndex(end);
13722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        attributes.add(fp);
13732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
13742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
13752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
13762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
13772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return toAppendTo;
13782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
13802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // Map pattern character to index
13822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int[] PATTERN_CHAR_TO_INDEX =
13832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
13842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
13852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //
13862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
13872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //       !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /
13882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
13892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
13902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
13912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //   @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
13921c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        -1, 22, 36, -1, 10,  9, 11,  0,  5, -1, -1, 16, 26,  2, -1, 31,
13932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //   P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _
13942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        -1, 27, -1,  8, -1, 30, 29, 13, 32, 18, 23, -1, -1, -1, -1, -1,
13952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //   `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
13961c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        -1, 14, 35, 25,  3, 19, -1, 21, 15, -1, -1,  4, -1,  6, -1, -1,
13972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    //   p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~
13982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        -1, 28, 34,  7, -1, 20, 24, 12, 33,  1, 17, -1, -1, -1, -1, -1,
13992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
14002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
14012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static int getIndexFromChar(char ch) {
14022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return ch < PATTERN_CHAR_TO_INDEX.length ? PATTERN_CHAR_TO_INDEX[ch & 0xff] : -1;
14032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
14042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
14052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // Map pattern character index to Calendar field number
14062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int[] PATTERN_INDEX_TO_CALENDAR_FIELD =
14072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
14082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*GyM*/ Calendar.ERA, Calendar.YEAR, Calendar.MONTH,
14092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*dkH*/ Calendar.DATE, Calendar.HOUR_OF_DAY, Calendar.HOUR_OF_DAY,
14102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*msS*/ Calendar.MINUTE, Calendar.SECOND, Calendar.MILLISECOND,
14112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*EDF*/ Calendar.DAY_OF_WEEK, Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK_IN_MONTH,
14122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*wWa*/ Calendar.WEEK_OF_YEAR, Calendar.WEEK_OF_MONTH, Calendar.AM_PM,
14132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*hKz*/ Calendar.HOUR, Calendar.HOUR, Calendar.ZONE_OFFSET,
14142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*Yeu*/ Calendar.YEAR_WOY, Calendar.DOW_LOCAL, Calendar.EXTENDED_YEAR,
14152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*gAZ*/ Calendar.JULIAN_DAY, Calendar.MILLISECONDS_IN_DAY, Calendar.ZONE_OFFSET /* also DST_OFFSET */,
14162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*v*/   Calendar.ZONE_OFFSET /* also DST_OFFSET */,
14172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*c*/   Calendar.DOW_LOCAL,
14182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*L*/   Calendar.MONTH,
14192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*Qq*/  Calendar.MONTH, Calendar.MONTH,
14202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*V*/   Calendar.ZONE_OFFSET /* also DST_OFFSET */,
14212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*U*/   Calendar.YEAR,
14222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*O*/   Calendar.ZONE_OFFSET /* also DST_OFFSET */,
14232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*Xx*/  Calendar.ZONE_OFFSET /* also DST_OFFSET */, Calendar.ZONE_OFFSET /* also DST_OFFSET */,
14242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*r*/   Calendar.EXTENDED_YEAR /* not an exact match */,
14251c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        /*bB*/  -1, -1 /* am/pm/midnight/noon and flexible day period fields; no mapping to calendar fields */
14262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*:*/   -1, /* => no useful mapping to any calendar field, can't use protected Calendar.BASE_FIELD_COUNT */
14272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
14282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
14292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // Map pattern character index to DateFormat field number
14302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int[] PATTERN_INDEX_TO_DATE_FORMAT_FIELD = {
14312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*GyM*/ DateFormat.ERA_FIELD, DateFormat.YEAR_FIELD, DateFormat.MONTH_FIELD,
14322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*dkH*/ DateFormat.DATE_FIELD, DateFormat.HOUR_OF_DAY1_FIELD, DateFormat.HOUR_OF_DAY0_FIELD,
14332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*msS*/ DateFormat.MINUTE_FIELD, DateFormat.SECOND_FIELD, DateFormat.FRACTIONAL_SECOND_FIELD,
14342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*EDF*/ DateFormat.DAY_OF_WEEK_FIELD, DateFormat.DAY_OF_YEAR_FIELD, DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD,
14352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*wWa*/ DateFormat.WEEK_OF_YEAR_FIELD, DateFormat.WEEK_OF_MONTH_FIELD, DateFormat.AM_PM_FIELD,
14362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*hKz*/ DateFormat.HOUR1_FIELD, DateFormat.HOUR0_FIELD, DateFormat.TIMEZONE_FIELD,
14372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*Yeu*/ DateFormat.YEAR_WOY_FIELD, DateFormat.DOW_LOCAL_FIELD, DateFormat.EXTENDED_YEAR_FIELD,
14382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*gAZ*/ DateFormat.JULIAN_DAY_FIELD, DateFormat.MILLISECONDS_IN_DAY_FIELD, DateFormat.TIMEZONE_RFC_FIELD,
14392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*v*/   DateFormat.TIMEZONE_GENERIC_FIELD,
14402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*c*/   DateFormat.STANDALONE_DAY_FIELD,
14412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*L*/   DateFormat.STANDALONE_MONTH_FIELD,
14422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*Qq*/  DateFormat.QUARTER_FIELD, DateFormat.STANDALONE_QUARTER_FIELD,
14432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*V*/   DateFormat.TIMEZONE_SPECIAL_FIELD,
14442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*U*/   DateFormat.YEAR_NAME_FIELD,
14452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*O*/   DateFormat.TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD,
14462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*Xx*/  DateFormat.TIMEZONE_ISO_FIELD, DateFormat.TIMEZONE_ISO_LOCAL_FIELD,
14472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*r*/   DateFormat.RELATED_YEAR,
14481c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        /*bB*/  DateFormat.AM_PM_MIDNIGHT_NOON_FIELD, DateFormat.FLEXIBLE_DAY_PERIOD_FIELD,
14492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*(no pattern character defined for this)*/   DateFormat.TIME_SEPARATOR,
14502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
14512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
14522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // Map pattern character index to DateFormat.Field
14532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final DateFormat.Field[] PATTERN_INDEX_TO_DATE_FORMAT_ATTRIBUTE = {
14542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*GyM*/ DateFormat.Field.ERA, DateFormat.Field.YEAR, DateFormat.Field.MONTH,
14552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*dkH*/ DateFormat.Field.DAY_OF_MONTH, DateFormat.Field.HOUR_OF_DAY1, DateFormat.Field.HOUR_OF_DAY0,
14562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*msS*/ DateFormat.Field.MINUTE, DateFormat.Field.SECOND, DateFormat.Field.MILLISECOND,
14572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*EDF*/ DateFormat.Field.DAY_OF_WEEK, DateFormat.Field.DAY_OF_YEAR, DateFormat.Field.DAY_OF_WEEK_IN_MONTH,
14582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*wWa*/ DateFormat.Field.WEEK_OF_YEAR, DateFormat.Field.WEEK_OF_MONTH, DateFormat.Field.AM_PM,
14592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*hKz*/ DateFormat.Field.HOUR1, DateFormat.Field.HOUR0, DateFormat.Field.TIME_ZONE,
14602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*Yeu*/ DateFormat.Field.YEAR_WOY, DateFormat.Field.DOW_LOCAL, DateFormat.Field.EXTENDED_YEAR,
14612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*gAZ*/ DateFormat.Field.JULIAN_DAY, DateFormat.Field.MILLISECONDS_IN_DAY, DateFormat.Field.TIME_ZONE,
14622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*v*/   DateFormat.Field.TIME_ZONE,
14632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*c*/   DateFormat.Field.DAY_OF_WEEK,
14642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*L*/   DateFormat.Field.MONTH,
14652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*Qq*/  DateFormat.Field.QUARTER, DateFormat.Field.QUARTER,
14662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*V*/   DateFormat.Field.TIME_ZONE,
14672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*U*/   DateFormat.Field.YEAR,
14682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*O*/   DateFormat.Field.TIME_ZONE,
14692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*Xx*/  DateFormat.Field.TIME_ZONE, DateFormat.Field.TIME_ZONE,
14702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*r*/   DateFormat.Field.RELATED_YEAR,
14711c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        /*bB*/  DateFormat.Field.AM_PM_MIDNIGHT_NOON, DateFormat.Field.FLEXIBLE_DAY_PERIOD,
14722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*(no pattern character defined for this)*/   DateFormat.Field.TIME_SEPARATOR,
14732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    };
14742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
14752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
14762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Returns a DateFormat.Field constant associated with the specified format pattern
14772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * character.
14782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
14792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param ch The pattern character
14802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return DateFormat.Field associated with the pattern character
14812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
14822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    protected DateFormat.Field patternCharToDateFormatField(char ch) {
14832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int patternCharIndex = getIndexFromChar(ch);
14842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (patternCharIndex != -1) {
14852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return PATTERN_INDEX_TO_DATE_FORMAT_ATTRIBUTE[patternCharIndex];
14862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
14872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return null;
14882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
14892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
14902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
14912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Formats a single field, given its pattern character.  Subclasses may
14922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * override this method in order to modify or add formatting
14932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * capabilities.
14942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param ch the pattern character
14952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param count the number of times ch is repeated in the pattern
14962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param beginOffset the offset of the output string at the start of
14972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * this field; used to set pos when appropriate
14982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param pos receives the position of a field, when appropriate
14992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param fmtData the symbols for this formatter
15002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
15012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    protected String subFormat(char ch, int count, int beginOffset,
15022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                               FieldPosition pos, DateFormatSymbols fmtData,
15032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                               Calendar cal)
15042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        throws IllegalArgumentException
15052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
15062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Note: formatData is ignored
15072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return subFormat(ch, count, beginOffset, 0, DisplayContext.CAPITALIZATION_NONE, pos, cal);
15082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
15092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
15102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     /**
15112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Formats a single field. This is the version called internally; it
15122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * adds fieldNum and capitalizationContext parameters.
15132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
15142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @deprecated This API is ICU internal only.
151593cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller     * @hide original deprecated declaration
1516836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller     * @hide draft / provisional / internal are hidden on Android
15172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
15182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Deprecated
15192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    protected String subFormat(char ch, int count, int beginOffset,
15202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                               int fieldNum, DisplayContext capitalizationContext,
15212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                               FieldPosition pos,
15222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                               Calendar cal)
15232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
15242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        StringBuffer buf = new StringBuffer();
15252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        subFormat(buf, ch, count, beginOffset, fieldNum, capitalizationContext, pos, cal);
15262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return buf.toString();
15272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
15282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
15292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller   /**
15302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Formats a single field; useFastFormat variant.  Reuses a
15312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * StringBuffer for results instead of creating a String on the
15322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * heap for each call.
15332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
15342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * NOTE We don't really need the beginOffset parameter, EXCEPT for
15352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the need to support the slow subFormat variant (above) which
15362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * has to pass it in to us.
15372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
15382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @deprecated This API is ICU internal only.
153993cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller * @hide original deprecated declaration
15401537b2f39245c07b00aa78c3600f7aebcb172490Neil Fuller * @hide draft / provisional / internal are hidden on Android
15412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
15422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Deprecated
15432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @SuppressWarnings("fallthrough")
15442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    protected void subFormat(StringBuffer buf,
15452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                             char ch, int count, int beginOffset,
15462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                             int fieldNum, DisplayContext capitalizationContext,
15472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                             FieldPosition pos,
15482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                             Calendar cal) {
15492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
15502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        final int maxIntCount = Integer.MAX_VALUE;
15512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        final int bufstart = buf.length();
15522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        TimeZone tz = cal.getTimeZone();
15532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        long date = cal.getTimeInMillis();
15542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String result = null;
15552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
15562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int patternCharIndex = getIndexFromChar(ch);
15572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (patternCharIndex == -1) {
15582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (ch == 'l') { // (SMALL LETTER L) deprecated placeholder for leap month marker, ignore
15592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return;
15602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
15612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                throw new IllegalArgumentException("Illegal pattern character " +
15622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                   "'" + ch + "' in \"" +
15632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                   pattern + '"');
15642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
15652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
15662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
15672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        final int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
15682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int value = 0;
15692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Don't get value unless it is useful
15702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (field >= 0) {
15712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            value = (patternCharIndex != DateFormat.RELATED_YEAR)? cal.get(field): cal.getRelatedYear();
15722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
15732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
15742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        NumberFormat currentNumberFormat = getNumberFormat(ch);
15752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        DateFormatSymbols.CapitalizationContextUsage capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.OTHER;
15762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
15772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        switch (patternCharIndex) {
15782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 0: // 'G' - ERA
15792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( cal.getType().equals("chinese") || cal.getType().equals("dangi") ) {
15802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // moved from ChineseDateFormat
15812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                zeroPaddingNumber(currentNumberFormat, buf, value, 1, 9);
15822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
15832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (count == 5) {
15842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    safeAppend(formatData.narrowEras, value, buf);
15852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.ERA_NARROW;
15862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else if (count == 4) {
15872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    safeAppend(formatData.eraNames, value, buf);
15882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.ERA_WIDE;
15892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
15902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    safeAppend(formatData.eras, value, buf);
15912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.ERA_ABBREV;
15922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
15932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
15942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
15952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 30: // 'U' - YEAR_NAME_FIELD
15962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (formatData.shortYearNames != null && value <= formatData.shortYearNames.length) {
15972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                safeAppend(formatData.shortYearNames, value-1, buf);
15982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
15992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
16001c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // else fall through to numeric year handling, do not break here
16012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 1: // 'y' - YEAR
16022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 18: // 'Y' - YEAR_WOY
16032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( override != null && (override.compareTo("hebr") == 0 || override.indexOf("y=hebr") >= 0) &&
16042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    value > HEBREW_CAL_CUR_MILLENIUM_START_YEAR && value < HEBREW_CAL_CUR_MILLENIUM_END_YEAR ) {
16052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                value -= HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
16062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
16072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* According to the specification, if the number of pattern letters ('y') is 2,
16082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * the year is truncated to 2 digits; otherwise it is interpreted as a number.
16092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * But the original code process 'y', 'yy', 'yyy' in the same way. and process
16102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * patterns with 4 or more than 4 'y' characters in the same way.
16112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * So I change the codes to meet the specification. [Richard/GCl]
16122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             */
16132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (count == 2) {
16142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                zeroPaddingNumber(currentNumberFormat,buf, value, 2, 2); // clip 1996 to 96
16152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else { //count = 1 or count > 2
16162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                zeroPaddingNumber(currentNumberFormat,buf, value, count, maxIntCount);
16172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
16182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
16192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 2: // 'M' - MONTH
16202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 26: // 'L' - STANDALONE MONTH
16212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( cal.getType().equals("hebrew")) {
16222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                boolean isLeap = HebrewCalendar.isLeapYear(cal.get(Calendar.YEAR));
16232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (isLeap && value == 6 && count >= 3 ) {
16242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    value = 13; // Show alternate form for Adar II in leap years in Hebrew calendar.
16252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
16262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (!isLeap && value >= 6 && count < 3 ) {
16272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    value--; // Adjust the month number down 1 in Hebrew non-leap years, i.e. Adar is 6, not 7.
16282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
16292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
16302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int isLeapMonth = (formatData.leapMonthPatterns != null && formatData.leapMonthPatterns.length >= DateFormatSymbols.DT_MONTH_PATTERN_COUNT)?
16312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                     cal.get(Calendar.IS_LEAP_MONTH): 0;
16322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // should consolidate the next section by using arrays of pointers & counts for the right symbols...
16332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (count == 5) {
16342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (patternCharIndex == 2) {
16352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    safeAppendWithMonthPattern(formatData.narrowMonths, value, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_FORMAT_NARROW]: null);
16362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
16372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    safeAppendWithMonthPattern(formatData.standaloneNarrowMonths, value, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_STANDALONE_NARROW]: null);
16382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
16392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.MONTH_NARROW;
16402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 4) {
16412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (patternCharIndex == 2) {
16422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    safeAppendWithMonthPattern(formatData.months, value, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_FORMAT_WIDE]: null);
16432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.MONTH_FORMAT;
16442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
16452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    safeAppendWithMonthPattern(formatData.standaloneMonths, value, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_STANDALONE_WIDE]: null);
16462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.MONTH_STANDALONE;
16472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
16482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 3) {
16492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (patternCharIndex == 2) {
16502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    safeAppendWithMonthPattern(formatData.shortMonths, value, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_FORMAT_ABBREV]: null);
16512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.MONTH_FORMAT;
16522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
16532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    safeAppendWithMonthPattern(formatData.standaloneShortMonths, value, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_STANDALONE_ABBREV]: null);
16542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.MONTH_STANDALONE;
16552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
16562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
16572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                StringBuffer monthNumber = new StringBuffer();
16582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                zeroPaddingNumber(currentNumberFormat, monthNumber, value+1, count, maxIntCount);
16592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                String[] monthNumberStrings = new String[1];
16602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                monthNumberStrings[0] = monthNumber.toString();
16612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                safeAppendWithMonthPattern(monthNumberStrings, 0, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_NUMERIC]: null);
16622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
16632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
16642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 4: // 'k' - HOUR_OF_DAY (1..24)
16652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (value == 0) {
16662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                zeroPaddingNumber(currentNumberFormat,buf,
16672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                  cal.getMaximum(Calendar.HOUR_OF_DAY)+1,
16682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                  count, maxIntCount);
16692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
16702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                zeroPaddingNumber(currentNumberFormat,buf, value, count, maxIntCount);
16712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
16722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
16732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 8: // 'S' - FRACTIONAL_SECOND
16742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Fractional seconds left-justify
16752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            {
16762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                numberFormat.setMinimumIntegerDigits(Math.min(3, count));
16772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                numberFormat.setMaximumIntegerDigits(maxIntCount);
16782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (count == 1) {
16792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    value /= 100;
16802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else if (count == 2) {
16812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    value /= 10;
16822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
16832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                FieldPosition p = new FieldPosition(-1);
1684f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert                numberFormat.format(value, buf, p);
16852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (count > 3) {
16862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    numberFormat.setMinimumIntegerDigits(count - 3);
16872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    numberFormat.format(0L, buf, p);
16882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
16892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
16902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
16912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 19: // 'e' - DOW_LOCAL (use DOW_LOCAL for numeric, DAY_OF_WEEK for format names)
16922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (count < 3) {
16932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                zeroPaddingNumber(currentNumberFormat,buf, value, count, maxIntCount);
16942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
16952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
16962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // For alpha day-of-week, we don't want DOW_LOCAL,
16972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // we need the standard DAY_OF_WEEK.
16982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            value = cal.get(Calendar.DAY_OF_WEEK);
16992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // fall through, do not break here
17002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 9: // 'E' - DAY_OF_WEEK
17012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (count == 5) {
17022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                safeAppend(formatData.narrowWeekdays, value, buf);
17032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_NARROW;
17042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 4) {
17052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                safeAppend(formatData.weekdays, value, buf);
17062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_FORMAT;
17072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 6 && formatData.shorterWeekdays != null) {
17082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                safeAppend(formatData.shorterWeekdays, value, buf);
17092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_FORMAT;
17102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {// count <= 3, use abbreviated form if exists
17112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                safeAppend(formatData.shortWeekdays, value, buf);
17122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_FORMAT;
17132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
17142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
17152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 14: // 'a' - AM_PM
17162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // formatData.ampmsNarrow may be null when deserializing DateFormatSymbolsfrom old version
17172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (count < 5 || formatData.ampmsNarrow == null) {
17182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                safeAppend(formatData.ampms, value, buf);
17192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
17202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                safeAppend(formatData.ampmsNarrow, value, buf);
17212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
17222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
17232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 15: // 'h' - HOUR (1..12)
17242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (value == 0) {
17252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                zeroPaddingNumber(currentNumberFormat,buf,
17262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                  cal.getLeastMaximum(Calendar.HOUR)+1,
17272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                  count, maxIntCount);
17282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
17292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                zeroPaddingNumber(currentNumberFormat,buf, value, count, maxIntCount);
17302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
17312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
17322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 17: // 'z' - TIMEZONE_FIELD
17342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (count < 4) {
17352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "z", "zz", "zzz"
17362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.SPECIFIC_SHORT, tz, date);
17372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.METAZONE_SHORT;
17382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
17392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.SPECIFIC_LONG, tz, date);
17402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.METAZONE_LONG;
17412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
17422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append(result);
17432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
17442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 23: // 'Z' - TIMEZONE_RFC_FIELD
17452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (count < 4) {
17462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // RFC822 format - equivalent to ISO 8601 local offset fixed width format
17472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.ISO_BASIC_LOCAL_FULL, tz, date);
17482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 5) {
17492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // ISO 8601 extended format
17502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.ISO_EXTENDED_FULL, tz, date);
17512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
17522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // long form, localized GMT pattern
17532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.LOCALIZED_GMT, tz, date);
17542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
17552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                buf.append(result);
17562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
17572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 24: // 'v' - TIMEZONE_GENERIC_FIELD
17582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (count == 1) {
17592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "v"
17602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.GENERIC_SHORT, tz, date);
17612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.METAZONE_SHORT;
17622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 4) {
17632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "vvvv"
17642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.GENERIC_LONG, tz, date);
17652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.METAZONE_LONG;
17662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
17672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append(result);
17682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
17692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 29: // 'V' - TIMEZONE_SPECIAL_FIELD
17702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (count == 1) {
17712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "V"
17722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.ZONE_ID_SHORT, tz, date);
17732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 2) {
17742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "VV"
17752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.ZONE_ID, tz, date);
17762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 3) {
17772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "VVV"
17782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.EXEMPLAR_LOCATION, tz, date);
17792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 4) {
17802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "VVVV"
17812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.GENERIC_LOCATION, tz, date);
17822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.ZONE_LONG;
17832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
17842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append(result);
17852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
17862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 31: // 'O' - TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD
17872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (count == 1) {
17882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "O" - Short Localized GMT format
17892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.LOCALIZED_GMT_SHORT, tz, date);
17902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 4) {
17912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "OOOO" - Localized GMT format
17922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.LOCALIZED_GMT, tz, date);
17932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
17942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append(result);
17952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
17962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 32: // 'X' - TIMEZONE_ISO_FIELD
17972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (count == 1) {
17982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "X" - ISO Basic/Short
17992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.ISO_BASIC_SHORT, tz, date);
18002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 2) {
18012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "XX" - ISO Basic/Fixed
18022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.ISO_BASIC_FIXED, tz, date);
18032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 3) {
18042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "XXX" - ISO Extended/Fixed
18052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.ISO_EXTENDED_FIXED, tz, date);
18062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 4) {
18072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "XXXX" - ISO Basic/Optional second field
18082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.ISO_BASIC_FULL, tz, date);
18092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 5) {
18102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "XXXXX" - ISO Extended/Optional second field
18112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.ISO_EXTENDED_FULL, tz, date);
18122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
18132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append(result);
18142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
18152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 33: // 'x' - TIMEZONE_ISO_LOCAL_FIELD
18162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (count == 1) {
18172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "x" - ISO Local Basic/Short
18182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.ISO_BASIC_LOCAL_SHORT, tz, date);
18192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 2) {
18202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "x" - ISO Local Basic/Fixed
18212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.ISO_BASIC_LOCAL_FIXED, tz, date);
18222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 3) {
18232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "xxx" - ISO Local Extended/Fixed
18242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.ISO_EXTENDED_LOCAL_FIXED, tz, date);
18252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 4) {
18262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "xxxx" - ISO Local Basic/Optional second field
18272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.ISO_BASIC_LOCAL_FULL, tz, date);
18282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 5) {
18292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // "xxxxx" - ISO Local Extended/Optional second field
18302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                result = tzFormat().format(Style.ISO_EXTENDED_LOCAL_FULL, tz, date);
18312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
18322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append(result);
18332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
18342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 25: // 'c' - STANDALONE DAY (use DOW_LOCAL for numeric, DAY_OF_WEEK for standalone)
18362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (count < 3) {
18372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                zeroPaddingNumber(currentNumberFormat,buf, value, 1, maxIntCount);
18382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
18392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
18402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // For alpha day-of-week, we don't want DOW_LOCAL,
18412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // we need the standard DAY_OF_WEEK.
18422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            value = cal.get(Calendar.DAY_OF_WEEK);
18432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (count == 5) {
18442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                safeAppend(formatData.standaloneNarrowWeekdays, value, buf);
18452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_NARROW;
18462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 4) {
18472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                safeAppend(formatData.standaloneWeekdays, value, buf);
18482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_STANDALONE;
18492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 6 && formatData.standaloneShorterWeekdays != null) {
18502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                safeAppend(formatData.standaloneShorterWeekdays, value, buf);
18512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_STANDALONE;
18522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else { // count == 3
18532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                safeAppend(formatData.standaloneShortWeekdays, value, buf);
18542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_STANDALONE;
18552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
18562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
18572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 27: // 'Q' - QUARTER
18582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (count >= 4) {
18592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                safeAppend(formatData.quarters, value/3, buf);
18602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 3) {
18612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                safeAppend(formatData.shortQuarters, value/3, buf);
18622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
18632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                zeroPaddingNumber(currentNumberFormat,buf, (value/3)+1, count, maxIntCount);
18642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
18652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
18662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        case 28: // 'q' - STANDALONE QUARTER
18672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (count >= 4) {
18682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                safeAppend(formatData.standaloneQuarters, value/3, buf);
18692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (count == 3) {
18702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                safeAppend(formatData.standaloneShortQuarters, value/3, buf);
18712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
18722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                zeroPaddingNumber(currentNumberFormat,buf, (value/3)+1, count, maxIntCount);
18732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
18742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
18751c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        case 35: // 'b' - am/pm/noon/midnight
18761c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        {
18771c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
18781c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // For ICU 57 output of "midnight" is temporarily suppressed.
18791c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
18801c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            int hour = cal.get(Calendar.HOUR_OF_DAY);
18811c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            String toAppend = null;
18821c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
18831c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // For "midnight" and "noon":
18841c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // Time, as displayed, must be exactly noon or midnight.
18851c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // This means minutes and seconds, if present, must be zero.
18861c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            if ((/*hour == 0 ||*/ hour == 12) &&
18871c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    (!hasMinute || cal.get(Calendar.MINUTE) == 0) &&
18881c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    (!hasSecond || cal.get(Calendar.SECOND) == 0)) {
18891c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                // Stealing am/pm value to use as our array index.
18901c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                // It works out: am/midnight are both 0, pm/noon are both 1,
18911c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                // 12 am is 12 midnight, and 12 pm is 12 noon.
18921c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                value = cal.get(Calendar.AM_PM);
18931c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
18941c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                if (count == 3) {
18951c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    toAppend = formatData.abbreviatedDayPeriods[value];
18961c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                } else if (count == 4 || count > 5) {
18971c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    toAppend = formatData.wideDayPeriods[value];
18981c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                } else { // count == 5
18991c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    toAppend = formatData.narrowDayPeriods[value];
19001c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                }
19011c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            }
19021c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
19031c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            if (toAppend == null) {
19041c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                // Time isn't exactly midnight or noon (as displayed) or localized string doesn't
19051c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                // exist for requested period. Fall back to am/pm instead.
19061c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                subFormat(buf, 'a', count, beginOffset, fieldNum, capitalizationContext, pos, cal);
19071c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            } else {
19081c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                buf.append(toAppend);
19091c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            }
19101c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
19111c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            break;
19121c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        }
19131c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        case 36: // 'B' - flexible day period
19141c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        {
19151c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // TODO: Maybe fetch the DayperiodRules during initialization (instead of at the first
19161c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // loading of an instance) if a relevant pattern character (b or B) is used.
19171c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            DayPeriodRules ruleSet = DayPeriodRules.getInstance(getLocale());
19181c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            if (ruleSet == null) {
19191c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                // Data doesn't exist for the locale we're looking for.
19201c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                // Fall back to am/pm.
19211c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                subFormat(buf, 'a', count, beginOffset, fieldNum, capitalizationContext, pos, cal);
19221c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                break;
19231c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            }
19241c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
19251c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // Get current display time.
19261c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            int hour = cal.get(Calendar.HOUR_OF_DAY);
19271c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            int minute = 0;
19281c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            int second = 0;
19291c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            if (hasMinute) { minute = cal.get(Calendar.MINUTE); }
19301c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            if (hasSecond) { second = cal.get(Calendar.SECOND); }
19311c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
19321c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // Determine day period.
19331c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            DayPeriodRules.DayPeriod periodType;
19341c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            if (hour == 0 && minute == 0 && second == 0 && ruleSet.hasMidnight()) {
19351c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                periodType = DayPeriodRules.DayPeriod.MIDNIGHT;
19361c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            } else if (hour == 12 && minute == 0 && second == 0 && ruleSet.hasNoon()) {
19371c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                periodType = DayPeriodRules.DayPeriod.NOON;
19381c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            } else {
19391c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                periodType = ruleSet.getDayPeriodForHour(hour);
19401c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            }
19411c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
19421c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
19431c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // For ICU 57 output of "midnight" is temporarily suppressed.
19441c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
19451c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // Rule set exists, therefore periodType can't be null.
19461c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // Get localized string.
19471c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            assert(periodType != null);
19481c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            String toAppend = null;
19491c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            int index;
19501c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
19511c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            if (periodType != DayPeriodRules.DayPeriod.AM && periodType != DayPeriodRules.DayPeriod.PM &&
19521c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    periodType != DayPeriodRules.DayPeriod.MIDNIGHT) {
19531c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                index = periodType.ordinal();
19541c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                if (count <= 3) {
19551c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    toAppend = formatData.abbreviatedDayPeriods[index];  // i.e. short
19561c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                } else if (count == 4 || count > 5) {
19571c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    toAppend = formatData.wideDayPeriods[index];
19581c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                } else {  // count == 5
19591c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    toAppend = formatData.narrowDayPeriods[index];
19601c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                }
19611c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            }
19621c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
19631c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
19641c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // Fallback schedule:
19651c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // Midnight/Noon -> General Periods -> AM/PM.
19661c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
19671c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // Midnight/Noon -> General Periods.
19681c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            if (toAppend == null &&
19691c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    (periodType == DayPeriodRules.DayPeriod.MIDNIGHT ||
19701c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                     periodType == DayPeriodRules.DayPeriod.NOON)) {
19711c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                periodType = ruleSet.getDayPeriodForHour(hour);
19721c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                index = periodType.ordinal();
19731c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
19741c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                if (count <= 3) {
19751c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    toAppend = formatData.abbreviatedDayPeriods[index];  // i.e. short
19761c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                } else if (count == 4 || count > 5) {
19771c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    toAppend = formatData.wideDayPeriods[index];
19781c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                } else {  // count == 5
19791c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    toAppend = formatData.narrowDayPeriods[index];
19801c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                }
19811c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            }
19821c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
19831c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // General Periods -> AM/PM.
19841c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            if (periodType == DayPeriodRules.DayPeriod.AM ||
19851c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    periodType == DayPeriodRules.DayPeriod.PM ||
19861c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    toAppend == null) {
19871c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                subFormat(buf, 'a', count, beginOffset, fieldNum, capitalizationContext, pos, cal);
19881c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            }
19891c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            else {
19901c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                buf.append(toAppend);
19911c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            }
19921c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
19931c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            break;
19941c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        }
19951c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        case 37: // TIME SEPARATOR (no pattern character currently defined, we should
19961c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                 // not get here but leave support in for future definition.
19972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append(formatData.getTimeSeparatorString());
19982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
19992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        default:
20002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // case 3: // 'd' - DATE
20012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // case 5: // 'H' - HOUR_OF_DAY (0..23)
20022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // case 6: // 'm' - MINUTE
20032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // case 7: // 's' - SECOND
20042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // case 10: // 'D' - DAY_OF_YEAR
20052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // case 11: // 'F' - DAY_OF_WEEK_IN_MONTH
20062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // case 12: // 'w' - WEEK_OF_YEAR
20072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // case 13: // 'W' - WEEK_OF_MONTH
20082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // case 16: // 'K' - HOUR (0..11)
20092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // case 20: // 'u' - EXTENDED_YEAR
20102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // case 21: // 'g' - JULIAN_DAY
20112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // case 22: // 'A' - MILLISECONDS_IN_DAY
20122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
20132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            zeroPaddingNumber(currentNumberFormat,buf, value, count, maxIntCount);
20142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            break;
20152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } // switch (patternCharIndex)
20162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
20172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (fieldNum == 0 && capitalizationContext != null && UCharacter.isLowerCase(buf.codePointAt(bufstart))) {
20182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            boolean titlecase = false;
20192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            switch (capitalizationContext) {
20202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                case CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE:
20212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    titlecase = true;
20222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
20232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                case CAPITALIZATION_FOR_UI_LIST_OR_MENU:
20242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                case CAPITALIZATION_FOR_STANDALONE:
20252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (formatData.capitalization != null) {
20262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        boolean[] transforms = formatData.capitalization.get(capContextUsageType);
20272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        titlecase = (capitalizationContext==DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU)?
20282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    transforms[0]: transforms[1];
20292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
20302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
20312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                default:
20322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   break;
20332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
20342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (titlecase) {
20352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (capitalizationBrkIter == null) {
20362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // should only happen when deserializing, etc.
20372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    capitalizationBrkIter = BreakIterator.getSentenceInstance(locale);
20382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
20392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                String firstField = buf.substring(bufstart); // bufstart or beginOffset, should be the same
20402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                String firstFieldTitleCase = UCharacter.toTitleCase(locale, firstField, capitalizationBrkIter,
20412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                     UCharacter.TITLECASE_NO_LOWERCASE | UCharacter.TITLECASE_NO_BREAK_ADJUSTMENT);
20422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                buf.replace(bufstart, buf.length(), firstFieldTitleCase);
20432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
20442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
20452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
20462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Set the FieldPosition (for the first occurrence only)
20472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (pos.getBeginIndex() == pos.getEndIndex()) {
20482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (pos.getField() == PATTERN_INDEX_TO_DATE_FORMAT_FIELD[patternCharIndex]) {
20492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                pos.setBeginIndex(beginOffset);
20502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                pos.setEndIndex(beginOffset + buf.length() - bufstart);
20512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (pos.getFieldAttribute() ==
20522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                       PATTERN_INDEX_TO_DATE_FORMAT_ATTRIBUTE[patternCharIndex]) {
20532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                pos.setBeginIndex(beginOffset);
20542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                pos.setEndIndex(beginOffset + buf.length() - bufstart);
20552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
20562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
20572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
20582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
20592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static void safeAppend(String[] array, int value, StringBuffer appendTo) {
20602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (array != null && value >= 0 && value < array.length) {
20612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            appendTo.append(array[value]);
20622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
20632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
20642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
20652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static void safeAppendWithMonthPattern(String[] array, int value, StringBuffer appendTo, String monthPattern) {
20662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (array != null && value >= 0 && value < array.length) {
20672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (monthPattern == null) {
20682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                appendTo.append(array[value]);
20692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
20701c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                String s = SimpleFormatterImpl.formatRawPattern(monthPattern, 1, 1, array[value]);
20711c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                appendTo.append(s);
20722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
20732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
20742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
20752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
20762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
20772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * PatternItem store parsed date/time field pattern information.
20782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
20792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static class PatternItem {
20802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        final char type;
20812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        final int length;
20822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        final boolean isNumeric;
20832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
20842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        PatternItem(char type, int length) {
20852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            this.type = type;
20862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            this.length = length;
20872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            isNumeric = isNumeric(type, length);
20882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
20892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
20902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
20912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static ICUCache<String, Object[]> PARSED_PATTERN_CACHE =
20922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        new SimpleCache<String, Object[]>();
20932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private transient Object[] patternItems;
20942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
20952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
20962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Returns parsed pattern items.  Each item is either String or
20972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * PatternItem.
20982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
20992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private Object[] getPatternItems() {
21002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (patternItems != null) {
21012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return patternItems;
21022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
21032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
21042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        patternItems = PARSED_PATTERN_CACHE.get(pattern);
21052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (patternItems != null) {
21062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return patternItems;
21072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
21082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
21092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean isPrevQuote = false;
21102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean inQuote = false;
21112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        StringBuilder text = new StringBuilder();
21122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        char itemType = 0;  // 0 for string literal, otherwise date/time pattern character
21132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int itemLength = 1;
21142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
21152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        List<Object> items = new ArrayList<Object>();
21162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
21172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = 0; i < pattern.length(); i++) {
21182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            char ch = pattern.charAt(i);
21192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (ch == '\'') {
21202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (isPrevQuote) {
21212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    text.append('\'');
21222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    isPrevQuote = false;
21232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
21242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    isPrevQuote = true;
21252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (itemType != 0) {
21262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        items.add(new PatternItem(itemType, itemLength));
21272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        itemType = 0;
21282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
21292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
21302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                inQuote = !inQuote;
21312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
21322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                isPrevQuote = false;
21332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (inQuote) {
21342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    text.append(ch);
21352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
21362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (isSyntaxChar(ch)) {
21372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // a date/time pattern character
21382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if (ch == itemType) {
21392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            itemLength++;
21402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        } else {
21412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            if (itemType == 0) {
21422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                if (text.length() > 0) {
21432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    items.add(text.toString());
21442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    text.setLength(0);
21452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                }
21462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            } else {
21472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                items.add(new PatternItem(itemType, itemLength));
21482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            }
21492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            itemType = ch;
21502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            itemLength = 1;
21512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
21522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else {
21532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // a string literal
21542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if (itemType != 0) {
21552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            items.add(new PatternItem(itemType, itemLength));
21562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            itemType = 0;
21572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
21582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        text.append(ch);
21592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
21602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
21612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
21622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
21632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // handle last item
21642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (itemType == 0) {
21652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (text.length() > 0) {
21662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                items.add(text.toString());
21672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                text.setLength(0);
21682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
21692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
21702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            items.add(new PatternItem(itemType, itemLength));
21712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
21722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
21732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        patternItems = items.toArray(new Object[items.size()]);
21742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
21752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        PARSED_PATTERN_CACHE.put(pattern, patternItems);
21762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
21772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return patternItems;
21782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
21792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
21802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
21812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Internal high-speed method.  Reuses a StringBuffer for results
21822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * instead of creating a String on the heap for each call.
21832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @deprecated This API is ICU internal only.
218493cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller     * @hide original deprecated declaration
2185836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller     * @hide draft / provisional / internal are hidden on Android
21862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
21872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Deprecated
21882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    protected void zeroPaddingNumber(NumberFormat nf,StringBuffer buf, int value,
21892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                     int minDigits, int maxDigits) {
21902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Note: Indian calendar uses negative value for a calendar
21912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // field. fastZeroPaddingNumber cannot handle negative numbers.
21922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // BTW, it looks like a design bug in the Indian calendar...
21932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (useLocalZeroPaddingNumberFormat && value >= 0) {
21942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            fastZeroPaddingNumber(buf, value, minDigits, maxDigits);
21952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
21962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            nf.setMinimumIntegerDigits(minDigits);
21972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            nf.setMaximumIntegerDigits(maxDigits);
21982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            nf.format(value, buf, new FieldPosition(-1));
21992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
22002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
22012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
22022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
22032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Overrides superclass method and
22041c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert     * This method also clears per field NumberFormat instances
22051c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert     * previously set by {@link #setNumberFormat(String, NumberFormat)}
22062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2207f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    @Override
22082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void setNumberFormat(NumberFormat newNumberFormat) {
22092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Override this method to update local zero padding number formatter
22102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        super.setNumberFormat(newNumberFormat);
22112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        initLocalZeroPaddingNumberFormat();
22122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        initializeTimeZoneFormat(true);
22132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
22142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (numberFormatters != null) {
22152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            numberFormatters = null;
22162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
22172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (overrideMap != null) {
22182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            overrideMap = null;
22192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
22202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
22212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
22222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
22232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Initializes transient fields for fast simple numeric formatting
22242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * code. This method should be called whenever number format is updated.
22252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
22262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void initLocalZeroPaddingNumberFormat() {
22272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (numberFormat instanceof DecimalFormat) {
22282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            decDigits = ((DecimalFormat)numberFormat).getDecimalFormatSymbols().getDigits();
22292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            useLocalZeroPaddingNumberFormat = true;
22302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if (numberFormat instanceof DateNumberFormat) {
22312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            decDigits = ((DateNumberFormat)numberFormat).getDigits();
22322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            useLocalZeroPaddingNumberFormat = true;
22332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
22342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            useLocalZeroPaddingNumberFormat = false;
22352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
22362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
22372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (useLocalZeroPaddingNumberFormat) {
22382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            decimalBuf = new char[DECIMAL_BUF_SIZE];
22392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
22402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
22412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
22422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // If true, use local version of zero padding number format
22432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private transient boolean useLocalZeroPaddingNumberFormat;
22442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private transient char[] decDigits;     // read-only - can be shared by multiple instances
22452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private transient char[] decimalBuf;    // mutable - one per instance
22462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final int DECIMAL_BUF_SIZE = 10; // sufficient for int numbers
22472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
22482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
22492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Lightweight zero padding integer number format function.
22502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
22512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Note: This implementation is almost equivalent to format method in DateNumberFormat.
22522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * In the method zeroPaddingNumber above should be able to use the one in DateNumberFormat,
22532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * but, it does not help IBM J9's JIT to optimize the performance much.  In simple repeative
22542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * date format test case, having local implementation is ~10% faster than using one in
22552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * DateNumberFormat on IBM J9 VM.  On Sun Hotspot VM, I do not see such difference.
22562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
22572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * -Yoshito
22582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
22592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void fastZeroPaddingNumber(StringBuffer buf, int value, int minDigits, int maxDigits) {
22602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int limit = decimalBuf.length < maxDigits ? decimalBuf.length : maxDigits;
22612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int index = limit - 1;
22622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        while (true) {
22632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            decimalBuf[index] = decDigits[(value % 10)];
22642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            value /= 10;
22652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (index == 0 || value == 0) {
22662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
22672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
22682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            index--;
22692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
22702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int padding = minDigits - (limit - index);
22712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        while (padding > 0 && index > 0) {
22722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            decimalBuf[--index] = decDigits[0];
22732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            padding--;
22742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
22752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        while (padding > 0) {
22762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // when pattern width is longer than decimalBuf, need extra
22772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // leading zeros - ticke#7595
22782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            buf.append(decDigits[0]);
22792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            padding--;
22802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
22812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        buf.append(decimalBuf, index, limit - index);
22822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
22832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
22842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
22852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Formats a number with the specified minimum and maximum number of digits.
22862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
22872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    protected String zeroPaddingNumber(long value, int minDigits, int maxDigits)
22882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
22892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        numberFormat.setMinimumIntegerDigits(minDigits);
22902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        numberFormat.setMaximumIntegerDigits(maxDigits);
22912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return numberFormat.format(value);
22922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
22932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
22942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
22952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Format characters that indicate numeric fields always.
22962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
22972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final String NUMERIC_FORMAT_CHARS = "ADdFgHhKkmrSsuWwYy";
22982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
22992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
23002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Format characters that indicate numeric fields when pattern lengh
23012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * is up to 2.
23022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
23032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final String NUMERIC_FORMAT_CHARS2 = "ceLMQq";
23042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
23052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
23062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Return true if the given format character, occuring count
23072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * times, represents a numeric field.
23082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
23092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final boolean isNumeric(char formatChar, int count) {
23102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return NUMERIC_FORMAT_CHARS.indexOf(formatChar) >= 0
23112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                || (count <= 2 && NUMERIC_FORMAT_CHARS2.indexOf(formatChar) >= 0);
23122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
23132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
23142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
23152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Overrides DateFormat
23162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see DateFormat
23172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2318f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    @Override
23192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void parse(String text, Calendar cal, ParsePosition parsePos)
23202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
23212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        TimeZone backupTZ = null;
23222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Calendar resultCal = null;
23232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (cal != calendar && !cal.getType().equals(calendar.getType())) {
23242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Different calendar type
23252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // We use the time/zone from the input calendar, but
23262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // do not use the input calendar for field calculation.
23272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            calendar.setTimeInMillis(cal.getTimeInMillis());
23282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            backupTZ = calendar.getTimeZone();
23292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            calendar.setTimeZone(cal.getTimeZone());
23302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            resultCal = cal;
23312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            cal = calendar;
23322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
23332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
23342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int pos = parsePos.getIndex();
23352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if(pos < 0) {
23362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            parsePos.setErrorIndex(0);
23372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
23382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
23392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int start = pos;
23402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
23411c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        // Hold the day period until everything else is parsed, because we need
23421c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        // the hour to interpret time correctly.
23431c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        // Using an one-element array for output parameter.
23441c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        Output<DayPeriodRules.DayPeriod> dayPeriod = new Output<DayPeriodRules.DayPeriod>(null);
23451c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
23462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Output<TimeType> tzTimeType = new Output<TimeType>(TimeType.UNKNOWN);
23472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean[] ambiguousYear = { false };
23482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
23492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // item index for the first numeric field within a contiguous numeric run
23502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int numericFieldStart = -1;
23512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // item length for the first numeric field within a contiguous numeric run
23522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int numericFieldLength = 0;
23532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // start index of numeric text run in the input text
23542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int numericStartPos = 0;
23551c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
23562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        MessageFormat numericLeapMonthFormatter = null;
23572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (formatData.leapMonthPatterns != null && formatData.leapMonthPatterns.length >= DateFormatSymbols.DT_MONTH_PATTERN_COUNT) {
23582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            numericLeapMonthFormatter = new MessageFormat(formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_NUMERIC], locale);
23592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
23602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
23612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Object[] items = getPatternItems();
23622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int i = 0;
23632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        while (i < items.length) {
23642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (items[i] instanceof PatternItem) {
23652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Handle pattern field
23662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                PatternItem field = (PatternItem)items[i];
23672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (field.isNumeric) {
23682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Handle fields within a run of abutting numeric fields.  Take
23692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // the pattern "HHmmss" as an example. We will try to parse
23702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // 2/2/2 characters of the input text, then if that fails,
23712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // 1/2/2.  We only adjust the width of the leftmost field; the
23722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // others remain fixed.  This allows "123456" => 12:34:56, but
23732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // "12345" => 1:23:45.  Likewise, for the pattern "yyyyMMdd" we
23742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // try 4/2/2, 3/2/2, 2/2/2, and finally 1/2/2.
23752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (numericFieldStart == -1) {
23762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // check if this field is followed by abutting another numeric field
23771c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                        if ((i + 1) < items.length
23781c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                                && (items[i + 1] instanceof PatternItem)
23792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                && ((PatternItem)items[i + 1]).isNumeric) {
23802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            // record the first numeric field within a numeric text run
23812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            numericFieldStart = i;
23822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            numericFieldLength = field.length;
23832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            numericStartPos = pos;
23842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
23852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
23862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
23872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (numericFieldStart != -1) {
23882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Handle a numeric field within abutting numeric fields
23892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int len = field.length;
23902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (numericFieldStart == i) {
23912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        len = numericFieldLength;
23922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
23932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
23942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Parse a numeric field
23952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    pos = subParse(text, pos, field.type, len,
23962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            true, false, ambiguousYear, cal, numericLeapMonthFormatter, tzTimeType);
23972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
23982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (pos < 0) {
23992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // If the parse fails anywhere in the numeric run, back up to the
24002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // start of the run and use shorter pattern length for the first
24012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // numeric field.
24022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        --numericFieldLength;
24032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if (numericFieldLength == 0) {
24042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            // can not make shorter any more
24052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            parsePos.setIndex(start);
24062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            parsePos.setErrorIndex(pos);
24072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            if (backupTZ != null) {
24082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                calendar.setTimeZone(backupTZ);
24092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            }
24102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            return;
24112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
24122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        i = numericFieldStart;
24132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        pos = numericStartPos;
24142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        continue;
24152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
24162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
24172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else if (field.type != 'l') { // (SMALL LETTER L) obsolete pattern char just gets ignored
24182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Handle a non-numeric field or a non-abutting numeric field
24192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    numericFieldStart = -1;
24202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
24212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int s = pos;
24222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    pos = subParse(text, pos, field.type, field.length,
24231c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                            false, true, ambiguousYear, cal, numericLeapMonthFormatter, tzTimeType, dayPeriod);
24241c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
24252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (pos < 0) {
24262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if (pos == ISOSpecialEra) {
24272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            // era not present, in special cases allow this to continue
24282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            pos = s;
24292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
24301c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                            if (i+1 < items.length) {
24311c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
24322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                String patl = null;
24332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                // if it will cause a class cast exception to String, we can't use it
24342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                try {
24352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    patl = (String)items[i+1];
24362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                } catch(ClassCastException cce) {
24372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    parsePos.setIndex(start);
24382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    parsePos.setErrorIndex(s);
24392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    if (backupTZ != null) {
24402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                        calendar.setTimeZone(backupTZ);
24412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    }
24422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    return;
24431c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                                }
24441c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
24452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                // get next item in pattern
24462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                if(patl == null)
24472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    patl = (String)items[i+1];
24482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                int plen = patl.length();
24492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                int idx=0;
24501c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
24511c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                                // White space characters found in pattern.
24522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                // Skip contiguous white spaces.
24532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                while (idx < plen) {
24542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
24552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    char pch = patl.charAt(idx);
24562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    if (PatternProps.isWhiteSpace(pch))
24572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                        idx++;
24582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    else
24592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                        break;
24602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                }
24611c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
24622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                // if next item in pattern is all whitespace, skip it
24632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                if (idx == plen) {
24642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    i++;
24652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                }
24662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
24672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            }
24682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        } else {
24692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            parsePos.setIndex(start);
24702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            parsePos.setErrorIndex(s);
24712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            if (backupTZ != null) {
24722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                calendar.setTimeZone(backupTZ);
24732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            }
24742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            return;
24751c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                        }
24762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
24772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
24782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
24792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
24802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Handle literal pattern text literal
24812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                numericFieldStart = -1;
24822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                boolean[] complete = new boolean[1];
24832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                pos = matchLiteral(text, pos, items, i, complete);
24842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (!complete[0]) {
24852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Set the position of mismatch
24862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    parsePos.setIndex(start);
24872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    parsePos.setErrorIndex(pos);
24882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (backupTZ != null) {
24892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        calendar.setTimeZone(backupTZ);
24902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
24912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return;
24922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
24932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
24942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            ++i;
24952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
24961c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
24972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Special hack for trailing "." after non-numeric field.
24982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (pos < text.length()) {
24992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            char extra = text.charAt(pos);
25002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (extra == '.' && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_WHITESPACE) && items.length != 0) {
25012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // only do if the last field is not numeric
25022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                Object lastItem = items[items.length - 1];
25032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (lastItem instanceof PatternItem && !((PatternItem)lastItem).isNumeric) {
25042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    pos++; // skip the extra "."
25052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
25062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
25072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
25082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
25091c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        // If dayPeriod is set, use it in conjunction with hour-of-day to determine am/pm.
25101c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        if (dayPeriod.value != null) {
25111c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            DayPeriodRules ruleSet = DayPeriodRules.getInstance(getLocale());
25121c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
25131c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            if (!cal.isSet(Calendar.HOUR) && !cal.isSet(Calendar.HOUR_OF_DAY)) {
25141c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                // If hour is not set, set time to the midpoint of current day period, overwriting
25151c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                // minutes if it's set.
25161c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                double midPoint = ruleSet.getMidPointForDayPeriod(dayPeriod.value);
25171c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
25181c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                // Truncate midPoint toward zero to get the hour.
25191c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                // Any leftover means it was a half-hour.
25201c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                int midPointHour = (int) midPoint;
25211c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                int midPointMinute = (midPoint - midPointHour) > 0 ? 30 : 0;
25221c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
25231c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                // No need to set am/pm because hour-of-day is set last therefore takes precedence.
25241c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                cal.set(Calendar.HOUR_OF_DAY, midPointHour);
25251c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                cal.set(Calendar.MINUTE, midPointMinute);
25261c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            } else {
25271c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                int hourOfDay;
25281c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
25291c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                if (cal.isSet(Calendar.HOUR_OF_DAY)) {  // Hour is parsed in 24-hour format.
25301c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    hourOfDay = cal.get(Calendar.HOUR_OF_DAY);
25311c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                } else {  // Hour is parsed in 12-hour format.
25321c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    hourOfDay = cal.get(Calendar.HOUR);
25331c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    // cal.get() turns 12 to 0 for 12-hour time; change 0 to 12
25341c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    // so 0 unambiguously means a 24-hour time from above.
25351c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    if (hourOfDay == 0) { hourOfDay = 12; }
25361c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                }
25371c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                assert(0 <= hourOfDay && hourOfDay <= 23);
25381c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
25391c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
25401c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                // If hour-of-day is 0 or 13 thru 23 then input time in unambiguously in 24-hour format.
25411c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                if (hourOfDay == 0 || (13 <= hourOfDay && hourOfDay <= 23)) {
25421c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    // Make hour-of-day take precedence over (hour + am/pm) by setting it again.
25431c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    cal.set(Calendar.HOUR_OF_DAY, hourOfDay);
25441c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                } else {
25451c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    // We have a 12-hour time and need to choose between am and pm.
25461c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    // Behave as if dayPeriod spanned 6 hours each way from its center point.
25471c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    // This will parse correctly for consistent time + period (e.g. 10 at night) as
25481c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    // well as provide a reasonable recovery for inconsistent time + period (e.g.
25491c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    // 9 in the afternoon).
25501c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
25511c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    // Assume current time is in the AM.
25521c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    // - Change 12 back to 0 for easier handling of 12am.
25531c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    // - Append minutes as fractional hours because e.g. 8:15 and 8:45 could be parsed
25541c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    // into different half-days if center of dayPeriod is at 14:30.
25551c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    // - cal.get(MINUTE) will return 0 if MINUTE is unset, which works.
25561c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    if (hourOfDay == 12) { hourOfDay = 0; }
25571c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    double currentHour = hourOfDay + cal.get(Calendar.MINUTE) / 60.0;
25581c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    double midPointHour = ruleSet.getMidPointForDayPeriod(dayPeriod.value);
25591c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
25601c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    double hoursAheadMidPoint = currentHour - midPointHour;
25611c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
25621c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    // Assume current time is in the AM.
25631c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    if (-6 <= hoursAheadMidPoint && hoursAheadMidPoint < 6) {
25641c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                        // Assumption holds; set time as such.
25651c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                        cal.set(Calendar.AM_PM, 0);
25661c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    } else {
25671c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                        cal.set(Calendar.AM_PM, 1);
25681c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    }
25691c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                }
25701c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            }
25711c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        }
25721c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
25732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // At this point the fields of Calendar have been set.  Calendar
25742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // will fill in default values for missing fields when the time
25752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // is computed.
25762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
25772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        parsePos.setIndex(pos);
25782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
25792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // This part is a problem:  When we call parsedDate.after, we compute the time.
25802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Take the date April 3 2004 at 2:30 am.  When this is first set up, the year
25812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // will be wrong if we're parsing a 2-digit year pattern.  It will be 1904.
25822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // April 3 1904 is a Sunday (unlike 2004) so it is the DST onset day.  2:30 am
25832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // is therefore an "impossible" time, since the time goes from 1:59 to 3:00 am
25842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // on that day.  It is therefore parsed out to fields as 3:30 am.  Then we
25852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // add 100 years, and get April 3 2004 at 3:30 am.  Note that April 3 2004 is
25862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // a Saturday, so it can have a 2:30 am -- and it should. [LIU]
25872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*
25882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          Date parsedDate = cal.getTime();
25892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          if( ambiguousYear[0] && !parsedDate.after(getDefaultCenturyStart()) ) {
25902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          cal.add(Calendar.YEAR, 100);
25912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          parsedDate = cal.getTime();
25922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller          }
25932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        */
25942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Because of the above condition, save off the fields in case we need to readjust.
25952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // The procedure we use here is not particularly efficient, but there is no other
25962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // way to do this given the API restrictions present in Calendar.  We minimize
25972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // inefficiency by only performing this computation when it might apply, that is,
25982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // when the two-digit year is equal to the start year, and thus might fall at the
25992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // front or the back of the default century.  This only works because we adjust
26002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // the year correctly to start with in other cases -- see subParse().
26012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        try {
26022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            TimeType tztype = tzTimeType.value;
26032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (ambiguousYear[0] || tztype != TimeType.UNKNOWN) {
26042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // We need a copy of the fields, and we need to avoid triggering a call to
26052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // complete(), which will recalculate the fields.  Since we can't access
26062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // the fields[] array in Calendar, we clone the entire object.  This will
26072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // stop working if Calendar.clone() is ever rewritten to call complete().
26082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                Calendar copy;
26092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (ambiguousYear[0]) { // the two-digit year == the default start year
26102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    copy = (Calendar)cal.clone();
26112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    Date parsedDate = copy.getTime();
26122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (parsedDate.before(getDefaultCenturyStart())) {
26132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // We can't use add here because that does a complete() first.
26142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        cal.set(Calendar.YEAR, getDefaultCenturyStartYear() + 100);
26152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
26162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
26172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (tztype != TimeType.UNKNOWN) {
26182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    copy = (Calendar)cal.clone();
26192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    TimeZone tz = copy.getTimeZone();
26202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    BasicTimeZone btz = null;
26212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (tz instanceof BasicTimeZone) {
26222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        btz = (BasicTimeZone)tz;
26232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
26242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
26252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Get local millis
26262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    copy.set(Calendar.ZONE_OFFSET, 0);
26272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    copy.set(Calendar.DST_OFFSET, 0);
26282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    long localMillis = copy.getTimeInMillis();
26292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
26302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Make sure parsed time zone type (Standard or Daylight)
26312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // matches the rule used by the parsed time zone.
26322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int[] offsets = new int[2];
26332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (btz != null) {
26342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if (tztype == TimeType.STANDARD) {
26352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            btz.getOffsetFromLocal(localMillis,
26362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    BasicTimeZone.LOCAL_STD, BasicTimeZone.LOCAL_STD, offsets);
26372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        } else {
26382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            btz.getOffsetFromLocal(localMillis,
26392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    BasicTimeZone.LOCAL_DST, BasicTimeZone.LOCAL_DST, offsets);
26402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
26412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else {
26422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // No good way to resolve ambiguous time at transition,
26432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // but following code work in most case.
26442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        tz.getOffset(localMillis, true, offsets);
26452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
26462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if (tztype == TimeType.STANDARD && offsets[1] != 0
26472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            || tztype == TimeType.DAYLIGHT && offsets[1] == 0) {
26482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            // Roll back one day and try it again.
26492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            // Note: This code assumes 1. timezone transition only happens
26502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            // once within 24 hours at max
26512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            // 2. the difference of local offsets at the transition is
26522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            // less than 24 hours.
26532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            tz.getOffset(localMillis - (24*60*60*1000), true, offsets);
26542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
26552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
26562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
26572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Now, compare the results with parsed type, either standard or
26582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // daylight saving time
26592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int resolvedSavings = offsets[1];
26602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (tztype == TimeType.STANDARD) {
26612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if (offsets[1] != 0) {
26622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            // Override DST_OFFSET = 0 in the result calendar
26632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            resolvedSavings = 0;
26642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
26652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else { // tztype == TZTYPE_DST
26662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if (offsets[1] == 0) {
26672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            if (btz != null) {
26682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                long time = localMillis + offsets[0];
26692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                // We use the nearest daylight saving time rule.
26702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                TimeZoneTransition beforeTrs, afterTrs;
26712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                long beforeT = time, afterT = time;
26722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                int beforeSav = 0, afterSav = 0;
26732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
26742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                // Search for DST rule before or on the time
26752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                while (true) {
26762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    beforeTrs = btz.getPreviousTransition(beforeT, true);
26772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    if (beforeTrs == null) {
26782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                        break;
26792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    }
26802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    beforeT = beforeTrs.getTime() - 1;
26812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    beforeSav = beforeTrs.getFrom().getDSTSavings();
26822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    if (beforeSav != 0) {
26832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                        break;
26842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    }
26852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                }
26862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
26872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                // Search for DST rule after the time
26882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                while (true) {
26892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    afterTrs = btz.getNextTransition(afterT, false);
26902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    if (afterTrs == null) {
26912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                        break;
26922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    }
26932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    afterT = afterTrs.getTime();
26942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    afterSav = afterTrs.getTo().getDSTSavings();
26952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    if (afterSav != 0) {
26962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                        break;
26972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    }
26982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                }
26992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
27002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                if (beforeTrs != null && afterTrs != null) {
27012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    if (time - beforeT > afterT - time) {
27022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                        resolvedSavings = afterSav;
27032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    } else {
27042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                        resolvedSavings = beforeSav;
27052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    }
27062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                } else if (beforeTrs != null && beforeSav != 0) {
27072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    resolvedSavings = beforeSav;
27082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                } else if (afterTrs != null && afterSav != 0) {
27092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    resolvedSavings = afterSav;
27102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                } else {
27112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    resolvedSavings = btz.getDSTSavings();
27122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                }
27132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            } else {
27142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                resolvedSavings = tz.getDSTSavings();
27152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            }
27162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            if (resolvedSavings == 0) {
27172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                // Final fallback
27182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                resolvedSavings = millisPerHour;
27192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            }
27202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
27212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
27222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    cal.set(Calendar.ZONE_OFFSET, offsets[0]);
27232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    cal.set(Calendar.DST_OFFSET, resolvedSavings);
27242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
27252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
27262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
27272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // An IllegalArgumentException will be thrown by Calendar.getTime()
27282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // if any fields are out of range, e.g., MONTH == 17.
27292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        catch (IllegalArgumentException e) {
27302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            parsePos.setErrorIndex(pos);
27312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            parsePos.setIndex(start);
27322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (backupTZ != null) {
27332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                calendar.setTimeZone(backupTZ);
27342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
27352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
27362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
27372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Set the parsed result if local calendar is used
27382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // instead of the input calendar
27392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (resultCal != null) {
27402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            resultCal.setTimeZone(cal.getTimeZone());
27412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            resultCal.setTimeInMillis(cal.getTimeInMillis());
27422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
27432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Restore the original time zone if required
27442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (backupTZ != null) {
27452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            calendar.setTimeZone(backupTZ);
27462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
27472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
27482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
27492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
27502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Matches text (starting at pos) with patl. Returns the new pos, and sets complete[0]
27512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * if it matched the entire text. Whitespace sequences are treated as singletons.
27522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <p>If isLenient and if we fail to match the first time, some special hacks are put into place.
27532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <ul><li>we are between date and time fields, then one or more whitespace characters
27542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in the text are accepted instead.</li>
27552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <ul><li>we are after a non-numeric field, and the text starts with a ".", we skip it.</li>
27562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * </ul>
27572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
27582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int matchLiteral(String text, int pos, Object[] items, int itemIndex, boolean[] complete) {
27592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int originalPos = pos;
27602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String patternLiteral = (String)items[itemIndex];
27612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int plen = patternLiteral.length();
27622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int tlen = text.length();
27632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int idx = 0;
27642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        while (idx < plen && pos < tlen) {
27652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            char pch = patternLiteral.charAt(idx);
27662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            char ich = text.charAt(pos);
27672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (PatternProps.isWhiteSpace(pch)
27682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                && PatternProps.isWhiteSpace(ich)) {
27692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // White space characters found in both patten and input.
27702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Skip contiguous white spaces.
27712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                while ((idx + 1) < plen &&
27722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        PatternProps.isWhiteSpace(patternLiteral.charAt(idx + 1))) {
27732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                     ++idx;
27742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
27752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                while ((pos + 1) < tlen &&
27762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        PatternProps.isWhiteSpace(text.charAt(pos + 1))) {
27772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                     ++pos;
27782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
27792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (pch != ich) {
27802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (ich == '.' && pos == originalPos && 0 < itemIndex && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_WHITESPACE)) {
27812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    Object before = items[itemIndex-1];
27822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (before instanceof PatternItem) {
27832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        boolean isNumeric = ((PatternItem) before).isNumeric;
27842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if (!isNumeric) {
27852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            ++pos; // just update pos
27862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            continue;
27872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
27882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
27892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else if ((pch == ' ' || pch == '.') && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_WHITESPACE)) {
27902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ++idx;
27912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    continue;
27922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else if (pos != originalPos && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_PARTIAL_LITERAL_MATCH)) {
27932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ++idx;
27942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    continue;
27952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
27962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
27972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
27982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            ++idx;
27992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            ++pos;
28002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
28012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        complete[0] = idx == plen;
28022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (complete[0] == false && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_WHITESPACE) && 0 < itemIndex && itemIndex < items.length - 1) {
28032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // If fully lenient, accept " "* for any text between a date and a time field
28042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // We don't go more lenient, because we don't want to accept "12/31" for "12:31".
28052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // People may be trying to parse for a date, then for a time.
28062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (originalPos < tlen) {
28072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                Object before = items[itemIndex-1];
28082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                Object after = items[itemIndex+1];
28092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (before instanceof PatternItem && after instanceof PatternItem) {
28102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    char beforeType = ((PatternItem) before).type;
28112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    char afterType = ((PatternItem) after).type;
28122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (DATE_PATTERN_TYPE.contains(beforeType) != DATE_PATTERN_TYPE.contains(afterType)) {
28132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        int newPos = originalPos;
28142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        while (true) {
28152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            char ich = text.charAt(newPos);
28162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            if (!PatternProps.isWhiteSpace(ich)) {
28172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                break;
28182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            }
28192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            ++newPos;
28202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
28212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        complete[0] = newPos > originalPos;
28222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        pos = newPos;
28232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
28242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
28252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
28262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
28272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return pos;
28282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
28291c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
28302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final UnicodeSet DATE_PATTERN_TYPE = new UnicodeSet("[GyYuUQqMLlwWd]").freeze();
28312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
28322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
28332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Attempt to match the text at a given position against an array of
28342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * strings.  Since multiple strings in the array may match (for
28352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * example, if the array contains "a", "ab", and "abc", all will match
28362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the input string "abcd") the longest match is returned.  As a side
28372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * effect, the given field of <code>cal</code> is set to the index
28382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of the best match, if there is one.
28392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param text the time text being parsed.
28402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param start where to start parsing.
28412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param field the date field being parsed.
28422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param data the string array to parsed.
28432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param cal
28442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the new start position if matching succeeded; a negative
28452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * number indicating matching failure, otherwise.  As a side effect,
28462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * sets the <code>cal</code> field <code>field</code> to the index
28472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of the best match, if matching succeeded.
28482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
28492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    protected int matchString(String text, int start, int field, String[] data, Calendar cal)
28502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
28512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return matchString(text, start, field, data, null, cal);
28522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
28532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
28542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
28552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Attempt to match the text at a given position against an array of
28562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * strings.  Since multiple strings in the array may match (for
28572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * example, if the array contains "a", "ab", and "abc", all will match
28582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the input string "abcd") the longest match is returned.  As a side
28592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * effect, the given field of <code>cal</code> is set to the index
28602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of the best match, if there is one.
28612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param text the time text being parsed.
28622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param start where to start parsing.
28632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param field the date field being parsed.
28642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param data the string array to parsed.
28652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param monthPattern leap month pattern, or null if none.
28662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param cal
28672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the new start position if matching succeeded; a negative
28682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * number indicating matching failure, otherwise.  As a side effect,
28692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * sets the <code>cal</code> field <code>field</code> to the index
28702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of the best match, if matching succeeded.
28712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @deprecated This API is ICU internal only.
2872836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller     * @hide draft / provisional / internal are hidden on Android
28732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
28742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Deprecated
28752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int matchString(String text, int start, int field, String[] data, String monthPattern, Calendar cal)
28762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
28772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int i = 0;
28782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int count = data.length;
28792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
28802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (field == Calendar.DAY_OF_WEEK) i = 1;
28812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
28822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // There may be multiple strings in the data[] array which begin with
28832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
28842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // We keep track of the longest match, and return that.  Note that this
28852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // unfortunately requires us to test all array elements.
28862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int bestMatchLength = 0, bestMatch = -1;
28872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int isLeapMonth = 0;
28882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int matchLength = 0;
28892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
28902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (; i<count; ++i)
28912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            {
28922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int length = data[i].length();
28932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Always compare if we have no match yet; otherwise only compare
28942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // against potentially better matches (longer strings).
28952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (length > bestMatchLength &&
28962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    (matchLength = regionMatchesWithOptionalDot(text, start, data[i], length)) >= 0)
28972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    {
28982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        bestMatch = i;
28992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        bestMatchLength = matchLength;
29002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        isLeapMonth = 0;
29012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
29022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (monthPattern != null) {
29031c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    String leapMonthName = SimpleFormatterImpl.formatRawPattern(
29041c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                            monthPattern, 1, 1, data[i]);
29052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    length = leapMonthName.length();
29062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (length > bestMatchLength &&
29072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        (matchLength = regionMatchesWithOptionalDot(text, start, leapMonthName, length)) >= 0)
29082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        {
29092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            bestMatch = i;
29102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            bestMatchLength = matchLength;
29112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            isLeapMonth = 1;
29122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
29132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 }
29142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
29152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (bestMatch >= 0)
29162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            {
29172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (field >= 0) {
29182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (field == Calendar.YEAR) {
29192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        bestMatch++; // only get here for cyclic year names, which match 1-based years 1-60
29202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
29212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    cal.set(field, bestMatch);
29222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (monthPattern != null) {
29232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        cal.set(Calendar.IS_LEAP_MONTH, isLeapMonth);
29242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
29252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
29262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return start + bestMatchLength;
29272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
29282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return ~start;
29292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
29302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
29312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int regionMatchesWithOptionalDot(String text, int start, String data, int length) {
29322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean matches = text.regionMatches(true, start, data, 0, length);
29332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (matches) {
29342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return length;
29352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
29362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (data.length() > 0 && data.charAt(data.length()-1) == '.') {
29372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (text.regionMatches(true, start, data, 0, length-1)) {
29382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return length - 1;
29392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
29402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
29412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return -1;
29422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
29432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
29442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
29452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Attempt to match the text at a given position against an array of quarter
29462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * strings.  Since multiple strings in the array may match (for
29472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * example, if the array contains "a", "ab", and "abc", all will match
29482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the input string "abcd") the longest match is returned.  As a side
29492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * effect, the given field of <code>cal</code> is set to the index
29502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of the best match, if there is one.
29512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param text the time text being parsed.
29522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param start where to start parsing.
29532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param field the date field being parsed.
29542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param data the string array to parsed.
29552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the new start position if matching succeeded; a negative
29562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * number indicating matching failure, otherwise.  As a side effect,
29572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * sets the <code>cal</code> field <code>field</code> to the index
29582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * of the best match, if matching succeeded.
29592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
29602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    protected int matchQuarterString(String text, int start, int field, String[] data, Calendar cal)
29612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
29622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int i = 0;
29632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int count = data.length;
29642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
29652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // There may be multiple strings in the data[] array which begin with
29662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
29672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // We keep track of the longest match, and return that.  Note that this
29682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // unfortunately requires us to test all array elements.
29692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int bestMatchLength = 0, bestMatch = -1;
29702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int matchLength = 0;
29712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (; i<count; ++i) {
29722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int length = data[i].length();
29732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Always compare if we have no match yet; otherwise only compare
29742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // against potentially better matches (longer strings).
29752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (length > bestMatchLength &&
29762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                (matchLength = regionMatchesWithOptionalDot(text, start, data[i], length)) >= 0) {
29772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
29782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                bestMatch = i;
29792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                bestMatchLength = matchLength;
29802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
29812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
29822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
29832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (bestMatch >= 0) {
29842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            cal.set(field, bestMatch * 3);
29852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return start + bestMatchLength;
29862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
29872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
29882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return -start;
29892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
29902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
29912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
29921c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert     * Similar to matchQuarterString but customized for day periods.
29931c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert     */
29941c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert    private int matchDayPeriodString(String text, int start, String[] data, int dataLength,
29951c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            Output<DayPeriodRules.DayPeriod> dayPeriod)
29961c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert    {
29971c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        int bestMatchLength = 0, bestMatch = -1;
29981c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        int matchLength = 0;
29991c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        for (int i = 0; i < dataLength; ++i) {
30001c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            // Only try matching if the string exists.
30011c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            if (data[i] != null) {
30021c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                int length = data[i].length();
30031c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                if (length > bestMatchLength &&
30041c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                        (matchLength = regionMatchesWithOptionalDot(text, start, data[i], length)) >= 0) {
30051c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    bestMatch = i;
30061c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    bestMatchLength = matchLength;
30071c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                }
30081c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            }
30091c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        }
30101c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
30111c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        if (bestMatch >= 0) {
30121c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            dayPeriod.value = DayPeriodRules.DayPeriod.VALUES[bestMatch];
30131c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            return start + bestMatchLength;
30141c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        }
30151c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
30161c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        return -start;
30171c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert    }
30181c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
30191c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert    /**
30202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Protected method that converts one field of the input string into a
30212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * numeric field value in <code>cal</code>.  Returns -start (for
30222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * ParsePosition) if failed.  Subclasses may override this method to
30232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * modify or add parsing capabilities.
30242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param text the time text to be parsed.
30252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param start where to start parsing.
30262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param ch the pattern character for the date field text to be parsed.
30272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param count the count of a pattern character.
30282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param obeyCount if true, then the next field directly abuts this one,
30292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * and we should use the count to know when to stop parsing.
30302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param ambiguousYear return parameter; upon return, if ambiguousYear[0]
30312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * is true, then a two-digit year was parsed and may need to be readjusted.
30322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param cal
30332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the new start position if matching succeeded; a negative
30342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * number indicating matching failure, otherwise.  As a side effect,
30352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * set the appropriate field of <code>cal</code> with the parsed
30362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * value.
30372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
30382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    protected int subParse(String text, int start, char ch, int count,
30392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                           boolean obeyCount, boolean allowNegative,
30402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                           boolean[] ambiguousYear, Calendar cal)
30412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
30422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return subParse(text, start, ch, count, obeyCount, allowNegative, ambiguousYear, cal, null, null);
30432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
30442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
30452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
30461c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert     * Overloading to provide default argument (null) for day period.
30471c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert     */
30481c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert    private int subParse(String text, int start, char ch, int count,
30491c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            boolean obeyCount, boolean allowNegative,
30501c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            boolean[] ambiguousYear, Calendar cal,
30511c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            MessageFormat numericLeapMonthFormatter, Output<TimeType> tzTimeType) {
30521c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        return subParse(text, start, ch, count, obeyCount, allowNegative, ambiguousYear, cal, null, null, null);
30531c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert    }
30541c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
30551c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert    /**
30562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Protected method that converts one field of the input string into a
30572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * numeric field value in <code>cal</code>.  Returns -start (for
30582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * ParsePosition) if failed.  Subclasses may override this method to
30592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * modify or add parsing capabilities.
30602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param text the time text to be parsed.
30612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param start where to start parsing.
30622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param ch the pattern character for the date field text to be parsed.
30632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param count the count of a pattern character.
30642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param obeyCount if true, then the next field directly abuts this one,
30652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * and we should use the count to know when to stop parsing.
30662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param ambiguousYear return parameter; upon return, if ambiguousYear[0]
30672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * is true, then a two-digit year was parsed and may need to be readjusted.
30682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param cal
30692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param numericLeapMonthFormatter if non-null, used to parse numeric leap months.
30702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param tzTimeType the type of parsed time zone - standard, daylight or unknown (output).
30712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *      This parameter can be null if caller does not need the information.
30722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the new start position if matching succeeded; a negative
30732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * number indicating matching failure, otherwise.  As a side effect,
30742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * set the appropriate field of <code>cal</code> with the parsed
30752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * value.
30762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @deprecated This API is ICU internal only.
3077836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller     * @hide draft / provisional / internal are hidden on Android
30782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
30792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Deprecated
30802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @SuppressWarnings("fallthrough")
30812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int subParse(String text, int start, char ch, int count,
30822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                           boolean obeyCount, boolean allowNegative,
30832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                           boolean[] ambiguousYear, Calendar cal,
30841c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                           MessageFormat numericLeapMonthFormatter, Output<TimeType> tzTimeType,
30851c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                           Output<DayPeriodRules.DayPeriod> dayPeriod)
30862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
30872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Number number = null;
30882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        NumberFormat currentNumberFormat = null;
30892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int value = 0;
30902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int i;
30912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        ParsePosition pos = new ParsePosition(0);
30922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
30932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int patternCharIndex = getIndexFromChar(ch);
30942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (patternCharIndex == -1) {
30952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return ~start;
30962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
30972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
30982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        currentNumberFormat = getNumberFormat(ch);
30992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
31002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex]; // -1 if irrelevant
31011c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
31022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (numericLeapMonthFormatter != null) {
31032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            numericLeapMonthFormatter.setFormatByArgumentIndex(0, currentNumberFormat);
31042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
31052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean isChineseCalendar = ( cal.getType().equals("chinese") || cal.getType().equals("dangi") );
31062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
31072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // If there are any spaces here, skip over them.  If we hit the end
31082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // of the string, then fail.
31092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (;;) {
31102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (start >= text.length()) {
31112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return ~start;
31122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
31132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int c = UTF16.charAt(text, start);
31142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (!UCharacter.isUWhiteSpace(c) || !PatternProps.isWhiteSpace(c)) {
31152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
31162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
31172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            start += UTF16.getCharCount(c);
31182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
31192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pos.setIndex(start);
31202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
31212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // We handle a few special cases here where we need to parse
31222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // a number value.  We handle further, more generic cases below.  We need
31232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // to handle some of them here because some fields require extra processing on
31242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // the parsed value.
31252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (patternCharIndex == 4 /*'k' HOUR_OF_DAY1_FIELD*/ ||
31262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            patternCharIndex == 15 /*'h' HOUR1_FIELD*/ ||
31272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            (patternCharIndex == 2 /*'M' MONTH_FIELD*/ && count <= 2) ||
31282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            patternCharIndex == 26 /*'L' STAND_ALONE_MONTH*/ ||
31292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            patternCharIndex == 19 /*'e' DOW_LOCAL*/ ||
31302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            patternCharIndex == 25 /*'c' STAND_ALONE_DAY_OF_WEEK*/ ||
31312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            patternCharIndex == 1 /*'y' YEAR */ || patternCharIndex == 18 /*'Y' YEAR_WOY */ ||
31322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            patternCharIndex == 30 /*'U' YEAR_NAME_FIELD, falls back to numeric */ ||
31332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            (patternCharIndex == 0 /*'G' ERA */ && isChineseCalendar) ||
31342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            patternCharIndex == 27 /* 'Q' - QUARTER*/ ||
31352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            patternCharIndex == 28 /* 'q' - STANDALONE QUARTER*/ ||
31362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            patternCharIndex == 8 /*'S' FRACTIONAL_SECOND */ )
31372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            {
31382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // It would be good to unify this with the obeyCount logic below,
31392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // but that's going to be difficult.
31401c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
31412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                boolean parsedNumericLeapMonth = false;
31422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (numericLeapMonthFormatter != null && (patternCharIndex == 2 || patternCharIndex == 26)) {
31432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // First see if we can parse month number with leap month pattern
31442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    Object[] args = numericLeapMonthFormatter.parse(text, pos);
31452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (args != null && pos.getIndex() > start && (args[0] instanceof Number)) {
31462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        parsedNumericLeapMonth = true;
31472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        number = (Number)args[0];
31482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        cal.set(Calendar.IS_LEAP_MONTH, 1);
31492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else {
31502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        pos.setIndex(start);
31512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        cal.set(Calendar.IS_LEAP_MONTH, 0);
31522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   }
31532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
31541c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
31552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (!parsedNumericLeapMonth) {
31562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (obeyCount) {
31572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if ((start+count) > text.length()) {
31582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            return ~start;
31592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
31602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        number = parseInt(text, count, pos, allowNegative,currentNumberFormat);
31612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else {
31622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        number = parseInt(text, pos, allowNegative,currentNumberFormat);
31632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
31642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (number == null && !allowNumericFallback(patternCharIndex)) {
31652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // only return if pattern is NOT one that allows numeric fallback
31662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        return ~start;
31672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
31682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
31692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
31702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (number != null) {
31712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    value = number.intValue();
31722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
31732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
31742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
31752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        switch (patternCharIndex)
31762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            {
31772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 0: // 'G' - ERA
31782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ( isChineseCalendar ) {
31792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Numeric era handling moved from ChineseDateFormat,
31802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // If we didn't have a number, already returned -start above
31812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    cal.set(Calendar.ERA, value);
31822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return pos.getIndex();
31832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
31842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int ps = 0;
31852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (count == 5) {
31862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ps = matchString(text, start, Calendar.ERA, formatData.narrowEras, null, cal);
31872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else if (count == 4) {
31882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ps = matchString(text, start, Calendar.ERA, formatData.eraNames, null, cal);
31892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
31902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ps = matchString(text, start, Calendar.ERA, formatData.eras, null, cal);
31912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
31922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
31932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // check return position, if it equals -start, then matchString error
31941c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                // special case the return code so we don't necessarily fail out until we
31952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // verify no year information also
31962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (ps == ~start)
31972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ps = ISOSpecialEra;
31982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
31991c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                return ps;
32001c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
32012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 1: // 'y' - YEAR
32022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 18: // 'Y' - YEAR_WOY
32032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // If there are 3 or more YEAR pattern characters, this indicates
32042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // that the year value is to be treated literally, without any
32052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // two-digit year adjustments (e.g., from "01" to 2001).  Otherwise
32062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // we made adjustments to place the 2-digit year in the proper
32072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // century, for parsed strings from "00" to "99".  Any other string
32082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // is treated literally:  "2250", "-1", "1", "002".
32092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* 'yy' is the only special case, 'y' is interpreted as number. [Richard/GCL]*/
32102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* Skip this for Chinese calendar, moved from ChineseDateFormat */
32112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ( override != null && (override.compareTo("hebr") == 0 || override.indexOf("y=hebr") >= 0) && value < 1000 ) {
32122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
32132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else if (count == 2 && (pos.getIndex() - start) == 2 && cal.haveDefaultCentury()
32142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    && UCharacter.isDigit(text.charAt(start))
32152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    && UCharacter.isDigit(text.charAt(start+1)))
32162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    {
32172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // Assume for example that the defaultCenturyStart is 6/18/1903.
32182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // This means that two-digit years will be forced into the range
32192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // 6/18/1903 to 6/17/2003.  As a result, years 00, 01, and 02
32202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // correspond to 2000, 2001, and 2002.  Years 04, 05, etc. correspond
32212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // to 1904, 1905, etc.  If the year is 03, then it is 2003 if the
32222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // other fields specify a date before 6/18, or 1903 if they specify a
32232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // date afterwards.  As a result, 03 is an ambiguous year.  All other
32242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // two-digit years are unambiguous.
32252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        int ambiguousTwoDigitYear = getDefaultCenturyStartYear() % 100;
32262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        ambiguousYear[0] = value == ambiguousTwoDigitYear;
32272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        value += (getDefaultCenturyStartYear()/100)*100 +
32282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            (value < ambiguousTwoDigitYear ? 100 : 0);
32292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
32302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                cal.set(field, value);
32312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
32322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Delayed checking for adjustment of Hebrew month numbers in non-leap years.
32332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (DelayedHebrewMonthCheck) {
32342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (!HebrewCalendar.isLeapYear(value)) {
32352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        cal.add(Calendar.MONTH,1);
32362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
32372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    DelayedHebrewMonthCheck = false;
32382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
32392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return pos.getIndex();
32402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 30: // 'U' - YEAR_NAME_FIELD
32412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (formatData.shortYearNames != null) {
32422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int newStart = matchString(text, start, Calendar.YEAR, formatData.shortYearNames, null, cal);
32432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (newStart > 0) {
32442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        return newStart;
32452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
32462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
32472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ( number != null && (getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC) || formatData.shortYearNames == null || value > formatData.shortYearNames.length) ) {
32482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    cal.set(Calendar.YEAR, value);
32492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return pos.getIndex();
32502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
32512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return ~start;
32522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 2: // 'M' - MONTH
32532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 26: // 'L' - STAND_ALONE_MONTH
32542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (count <= 2 || (number != null && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC))) {
32552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // i.e., M/MM, L/LL or lenient & have a number
32562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Don't want to parse the month if it is a string
32572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // while pattern uses numeric style: M/MM, L/LL.
32582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // [We computed 'value' above.]
32592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    cal.set(Calendar.MONTH, value - 1);
32602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // When parsing month numbers from the Hebrew Calendar, we might need
32612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // to adjust the month depending on whether or not it was a leap year.
32622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // We may or may not yet know what year it is, so might have to delay
32632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // checking until the year is parsed.
32642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (cal.getType().equals("hebrew") && value >= 6) {
32652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if (cal.isSet(Calendar.YEAR)) {
32662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            if (!HebrewCalendar.isLeapYear(cal.get(Calendar.YEAR))) {
32672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                cal.set(Calendar.MONTH, value);
32682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            }
32692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        } else {
32702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            DelayedHebrewMonthCheck = true;
32712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
32722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
32732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return pos.getIndex();
32742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
32752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // count >= 3 // i.e., MMM/MMMM or LLL/LLLL
32762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Want to be able to parse both short and long forms.
32772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    boolean haveMonthPat = (formatData.leapMonthPatterns != null && formatData.leapMonthPatterns.length >= DateFormatSymbols.DT_MONTH_PATTERN_COUNT);
32782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Try count == 4 first:, unless we're strict
32792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int newStart = 0;
32802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
32812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        newStart = (patternCharIndex == 2)?
32822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            matchString(text, start, Calendar.MONTH, formatData.months,
32832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    (haveMonthPat)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_FORMAT_WIDE]: null, cal):
32842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            matchString(text, start, Calendar.MONTH, formatData.standaloneMonths,
32852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    (haveMonthPat)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_STANDALONE_WIDE]: null, cal);
32862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (newStart > 0) {
32872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        return newStart;
32882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
32891c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    }
32902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // count == 4 failed, now try count == 3
32912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
32922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        return (patternCharIndex == 2)?
32932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                matchString(text, start, Calendar.MONTH, formatData.shortMonths,
32942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                        (haveMonthPat)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_FORMAT_ABBREV]: null, cal):
32952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                matchString(text, start, Calendar.MONTH, formatData.standaloneShortMonths,
32962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                        (haveMonthPat)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_STANDALONE_ABBREV]: null, cal);
32972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
32982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return newStart;
32992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
33002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 4: // 'k' - HOUR_OF_DAY (1..24)
33012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // [We computed 'value' above.]
33022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (value == cal.getMaximum(Calendar.HOUR_OF_DAY)+1) {
33032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    value = 0;
33042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
33052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                cal.set(Calendar.HOUR_OF_DAY, value);
33062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return pos.getIndex();
33072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 8: // 'S' - FRACTIONAL_SECOND
33082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Fractional seconds left-justify
33092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                i = pos.getIndex() - start;
33102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (i < 3) {
33112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    while (i < 3) {
33122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        value *= 10;
33132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        i++;
33142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
33152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
33162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int a = 1;
33172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    while (i > 3) {
33182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        a *= 10;
33192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        i--;
33202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
33212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    value /= a;
33222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
33232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                cal.set(Calendar.MILLISECOND, value);
33242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return pos.getIndex();
33252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 19: // 'e' - DOW_LOCAL
33261c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                if(count <= 2 || (number != null && (getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC))) ) {
33272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // i.e. e/ee or lenient and have a number
33282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    cal.set(field, value);
33292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return pos.getIndex();
33302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
33312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // else for eee-eeeeee, fall through to EEE-EEEEEE handling
33321c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                //$FALL-THROUGH$
33332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 9: { // 'E' - DAY_OF_WEEK
33342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Want to be able to parse at least wide, abbrev, short, and narrow forms.
33352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int newStart = 0;
33362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
33372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.weekdays, null, cal)) > 0) { // try EEEE wide
33382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        return newStart;
33391c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    }
33402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
33412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
33422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.shortWeekdays, null, cal)) > 0) { // try EEE abbrev
33432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        return newStart;
33441c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    }
33452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
33462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 6) {
33472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (formatData.shorterWeekdays != null) {
33482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.shorterWeekdays, null, cal)) > 0) { // try EEEEEE short
33492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            return newStart;
33502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
33512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
33522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
33532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 5) {
33542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (formatData.narrowWeekdays != null) {
33552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.narrowWeekdays, null, cal)) > 0) { // try EEEEE narrow
33562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            return newStart;
33572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
33582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
33592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
33602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return newStart;
33612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
33622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 25: { // 'c' - STAND_ALONE_DAY_OF_WEEK
33631c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                if(count == 1 || (number != null && (getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC))) ) {
33642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // i.e. c or lenient and have a number
33652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    cal.set(field, value);
33662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return pos.getIndex();
33672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
33682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Want to be able to parse at least wide, abbrev, short forms.
33692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int newStart = 0;
33702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
33712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.standaloneWeekdays, null, cal)) > 0) { // try cccc wide
33722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        return newStart;
33731c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    }
33742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
33752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
33762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.standaloneShortWeekdays, null, cal)) > 0) { // try ccc abbrev
33772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        return newStart;
33782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
33792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
33802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 6) {
33812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (formatData.standaloneShorterWeekdays != null) {
33822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        return matchString(text, start, Calendar.DAY_OF_WEEK, formatData.standaloneShorterWeekdays, null, cal); // try cccccc short
33832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
33842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
33852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return newStart;
33862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
33872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 14: { // 'a' - AM_PM
33882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Optionally try both wide/abbrev and narrow forms.
33892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // formatData.ampmsNarrow may be null when deserializing DateFormatSymbolsfrom old version,
33902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // in which case our only option is wide form
33912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int newStart = 0;
33922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // try wide/abbrev a-aaaa
33932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if(formatData.ampmsNarrow == null || count < 5 || getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH)) {
33942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ((newStart = matchString(text, start, Calendar.AM_PM, formatData.ampms, null, cal)) > 0) {
33952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        return newStart;
33962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
33972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
33982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // try narrow aaaaa
33992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if(formatData.ampmsNarrow != null && (count >= 5 || getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH))) {
34002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ((newStart = matchString(text, start, Calendar.AM_PM, formatData.ampmsNarrow, null, cal)) > 0) {
34012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        return newStart;
34022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
34032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
34042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // no matches for given options
34052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return ~start;
34062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
34072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 15: // 'h' - HOUR (1..12)
34082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // [We computed 'value' above.]
34092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (value == cal.getLeastMaximum(Calendar.HOUR)+1) {
34102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    value = 0;
34112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
34122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                cal.set(Calendar.HOUR, value);
34132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return pos.getIndex();
34142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 17: // 'z' - ZONE_OFFSET
34152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            {
34162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                Style style = (count < 4) ? Style.SPECIFIC_SHORT : Style.SPECIFIC_LONG;
34172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
34182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (tz != null) {
34192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    cal.setTimeZone(tz);
34202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return pos.getIndex();
34212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
34222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return ~start;
34232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
34242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 23: // 'Z' - TIMEZONE_RFC
34252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            {
34262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                Style style = (count < 4) ? Style.ISO_BASIC_LOCAL_FULL : ((count == 5) ? Style.ISO_EXTENDED_FULL : Style.LOCALIZED_GMT);
34272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
34282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (tz != null) {
34292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    cal.setTimeZone(tz);
34302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return pos.getIndex();
34312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
34322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return ~start;
34332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
34342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 24: // 'v' - TIMEZONE_GENERIC
34352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            {
34362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Note: 'v' only supports count 1 and 4
34372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                Style style = (count < 4) ? Style.GENERIC_SHORT : Style.GENERIC_LONG;
34382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
34392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (tz != null) {
34402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    cal.setTimeZone(tz);
34412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return pos.getIndex();
34422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
34432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return ~start;
34442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
34452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 29: // 'V' - TIMEZONE_SPECIAL
34462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            {
34472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                Style style = null;
34482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                switch (count) {
34492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                case 1:
34502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    style = Style.ZONE_ID_SHORT;
34512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
34522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                case 2:
34532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    style = Style.ZONE_ID;
34542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
34552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                case 3:
34562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    style = Style.EXEMPLAR_LOCATION;
34572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
34582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                default:
34592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    style = Style.GENERIC_LOCATION;
34602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
34612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
34622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
34632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (tz != null) {
34642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    cal.setTimeZone(tz);
34652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return pos.getIndex();
34662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
34672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return ~start;
34682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
34692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 31: // 'O' - TIMEZONE_LOCALIZED_GMT_OFFSET
34702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            {
34712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                Style style = (count < 4) ? Style.LOCALIZED_GMT_SHORT : Style.LOCALIZED_GMT;
34722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
34732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (tz != null) {
34742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    cal.setTimeZone(tz);
34752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return pos.getIndex();
34762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
34772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return ~start;
34782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
34792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 32: // 'X' - TIMEZONE_ISO
34802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            {
34812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                Style style;
34822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                switch (count) {
34832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                case 1:
34842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    style = Style.ISO_BASIC_SHORT;
34852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
34862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                case 2:
34872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    style = Style.ISO_BASIC_FIXED;
34882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
34892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                case 3:
34902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    style = Style.ISO_EXTENDED_FIXED;
34912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
34922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                case 4:
34932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    style = Style.ISO_BASIC_FULL;
34942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
34952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                default: // count >= 5
34962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    style = Style.ISO_EXTENDED_FULL;
34972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
34982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
34992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
35002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (tz != null) {
35012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    cal.setTimeZone(tz);
35022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return pos.getIndex();
35032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
35042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return ~start;
35052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
35062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 33: // 'x' - TIMEZONE_ISO_LOCAL
35072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            {
35082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                Style style;
35092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                switch (count) {
35102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                case 1:
35112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    style = Style.ISO_BASIC_LOCAL_SHORT;
35122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
35132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                case 2:
35142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    style = Style.ISO_BASIC_LOCAL_FIXED;
35152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
35162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                case 3:
35172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    style = Style.ISO_EXTENDED_LOCAL_FIXED;
35182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
35192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                case 4:
35202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    style = Style.ISO_BASIC_LOCAL_FULL;
35212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
35222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                default: // count >= 5
35232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    style = Style.ISO_EXTENDED_LOCAL_FULL;
35242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
35252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
35262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
35272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (tz != null) {
35282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    cal.setTimeZone(tz);
35292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return pos.getIndex();
35302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
35312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return ~start;
35322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
35332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 27: // 'Q' - QUARTER
35341c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                if (count <= 2 || (number != null && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC))) {
35352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // i.e., Q or QQ. or lenient & have number
35362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Don't want to parse the quarter if it is a string
35372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // while pattern uses numeric style: Q or QQ.
35382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // [We computed 'value' above.]
35392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    cal.set(Calendar.MONTH, (value - 1) * 3);
35402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return pos.getIndex();
35412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
35422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // count >= 3 // i.e., QQQ or QQQQ
35432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Want to be able to parse both short and long forms.
35442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Try count == 4 first:
35452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int newStart = 0;
35462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
35472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if((newStart = matchQuarterString(text, start, Calendar.MONTH, formatData.quarters, cal)) > 0) {
35482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            return newStart;
35492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
35502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
35512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // count == 4 failed, now try count == 3
35522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
35532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        return matchQuarterString(text, start, Calendar.MONTH,
35542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                           formatData.shortQuarters, cal);
35552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
35562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return newStart;
35572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
35582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
35592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case 28: // 'q' - STANDALONE QUARTER
35601c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                if (count <= 2 || (number != null && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC))) {
35612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // i.e., q or qq. or lenient & have number
35622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Don't want to parse the quarter if it is a string
35632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // while pattern uses numeric style: q or qq.
35642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // [We computed 'value' above.]
35652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    cal.set(Calendar.MONTH, (value - 1) * 3);
35662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return pos.getIndex();
35672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
35682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // count >= 3 // i.e., qqq or qqqq
35692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Want to be able to parse both short and long forms.
35702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // Try count == 4 first:
35712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int newStart = 0;
35722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
35732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        if((newStart = matchQuarterString(text, start, Calendar.MONTH, formatData.standaloneQuarters, cal)) > 0) {
35742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            return newStart;
35752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        }
35762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
35772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // count == 4 failed, now try count == 3
35782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
35792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        return matchQuarterString(text, start, Calendar.MONTH,
35802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                           formatData.standaloneShortQuarters, cal);
35812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
35822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return newStart;
35832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
35842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
35851c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            case 37: // TIME SEPARATOR (no pattern character currently defined, we should
35861c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                     // not get here but leave support in for future definition.
35872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            {
35882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Try matching a time separator.
35892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ArrayList<String> data = new ArrayList<String>(3);
35902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                data.add(formatData.getTimeSeparatorString());
35912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
35922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Add the default, if different from the locale.
35932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (!formatData.getTimeSeparatorString().equals(DateFormatSymbols.DEFAULT_TIME_SEPARATOR)) {
35942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    data.add(DateFormatSymbols.DEFAULT_TIME_SEPARATOR);
35952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
35962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
35972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // If lenient, add also the alternate, if different from the locale.
35982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_PARTIAL_LITERAL_MATCH) &&
35992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        !formatData.getTimeSeparatorString().equals(DateFormatSymbols.ALTERNATE_TIME_SEPARATOR)) {
36002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    data.add(DateFormatSymbols.ALTERNATE_TIME_SEPARATOR);
36012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
36022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
36032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return matchString(text, start, -1 /* => nothing to set */, data.toArray(new String[0]), cal);
36042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
36052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
36061c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            case 35: // 'b' -- fixed day period (am/pm/midnight/noon)
36071c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            {
36081c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                int ampmStart = subParse(text, start, 'a', count, obeyCount, allowNegative, ambiguousYear, cal,
36091c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                        numericLeapMonthFormatter, tzTimeType, dayPeriod);
36101c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
36111c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                if (ampmStart > 0) {
36121c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    return ampmStart;
36131c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                } else {
36141c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    int newStart = 0;
36151c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
36161c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                        if ((newStart = matchDayPeriodString(
36171c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                                text, start, formatData.abbreviatedDayPeriods, 2, dayPeriod)) > 0) {
36181c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                            return newStart;
36191c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                        }
36201c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    }
36211c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
36221c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                        if ((newStart = matchDayPeriodString(
36231c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                                text, start, formatData.wideDayPeriods, 2, dayPeriod)) > 0) {
36241c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                            return newStart;
36251c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                        }
36261c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    }
36271c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
36281c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                        if ((newStart = matchDayPeriodString(
36291c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                                text, start, formatData.narrowDayPeriods, 2, dayPeriod)) > 0) {
36301c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                            return newStart;
36311c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                        }
36321c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    }
36331c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
36341c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    return newStart;
36351c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                }
36361c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            }
36371c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
36381c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            case 36: // 'B' -- flexible day period
36391c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            {
36401c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                int newStart = 0;
36411c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
36421c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    if ((newStart = matchDayPeriodString(
36431c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                            text, start, formatData.abbreviatedDayPeriods,
36441c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                            formatData.abbreviatedDayPeriods.length, dayPeriod)) > 0) {
36451c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                        return newStart;
36461c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    }
36471c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                }
36481c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
36491c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    if ((newStart = matchDayPeriodString(
36501c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                            text, start, formatData.wideDayPeriods,
36511c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                            formatData.wideDayPeriods.length, dayPeriod)) > 0) {
36521c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                        return newStart;
36531c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    }
36541c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                }
36551c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
36561c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    if ((newStart = matchDayPeriodString(
36571c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                            text, start, formatData.narrowDayPeriods,
36581c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                            formatData.narrowDayPeriods.length, dayPeriod)) > 0) {
36591c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                        return newStart;
36601c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    }
36611c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                }
36621c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
36631c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                return newStart;
36641c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            }
36651c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
36662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            default:
36672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // case 3: // 'd' - DATE
36682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // case 5: // 'H' - HOUR_OF_DAY (0..23)
36692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // case 6: // 'm' - MINUTE
36702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // case 7: // 's' - SECOND
36712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // case 10: // 'D' - DAY_OF_YEAR
36722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // case 11: // 'F' - DAY_OF_WEEK_IN_MONTH
36732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // case 12: // 'w' - WEEK_OF_YEAR
36742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // case 13: // 'W' - WEEK_OF_MONTH
36751c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                // case 16: // 'K' - HOUR (0..11)
36762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // case 20: // 'u' - EXTENDED_YEAR
36772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // case 21: // 'g' - JULIAN_DAY
36782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // case 22: // 'A' - MILLISECONDS_IN_DAY
36792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // case 34: //
36802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
36812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Handle "generic" fields
36822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (obeyCount) {
36832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if ((start+count) > text.length()) return -start;
36842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    number = parseInt(text, count, pos, allowNegative,currentNumberFormat);
36852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
36862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    number = parseInt(text, pos, allowNegative,currentNumberFormat);
36872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
36882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (number != null) {
36892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (patternCharIndex != DateFormat.RELATED_YEAR) {
36902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        cal.set(field, number.intValue());
36912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else {
36922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        cal.setRelatedYear(number.intValue());
36932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
36942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return pos.getIndex();
36952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
36962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return ~start;
36972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
36982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
36992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
37002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
37012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * return true if the pattern specified by patternCharIndex is one that allows
37022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * numeric fallback regardless of actual pattern size.
37032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
37042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private boolean allowNumericFallback(int patternCharIndex) {
37052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (patternCharIndex == 26 /*'L' STAND_ALONE_MONTH*/ ||
37062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            patternCharIndex == 19 /*'e' DOW_LOCAL*/ ||
37072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            patternCharIndex == 25 /*'c' STAND_ALONE_DAY_OF_WEEK*/ ||
37082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            patternCharIndex == 30 /*'U' YEAR_NAME_FIELD*/ ||
37092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            patternCharIndex == 27 /* 'Q' - QUARTER*/ ||
37102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            patternCharIndex == 28 /* 'q' - STANDALONE QUARTER*/) {
37112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return true;
37122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
37132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return false;
37142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
37151c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
37162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
37172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Parse an integer using numberFormat.  This method is semantically
37182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * const, but actually may modify fNumberFormat.
37192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
37202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private Number parseInt(String text,
37212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            ParsePosition pos,
37222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            boolean allowNegative,
37232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            NumberFormat fmt) {
37242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return parseInt(text, -1, pos, allowNegative, fmt);
37252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
37262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
37272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
37282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Parse an integer using numberFormat up to maxDigits.
37292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
37302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private Number parseInt(String text,
37312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            int maxDigits,
37322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            ParsePosition pos,
37332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            boolean allowNegative,
37342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            NumberFormat fmt) {
37352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Number number;
37362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int oldPos = pos.getIndex();
37372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (allowNegative) {
37382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            number = fmt.parse(text, pos);
37392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
37402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Invalidate negative numbers
37412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (fmt instanceof DecimalFormat) {
37422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                String oldPrefix = ((DecimalFormat)fmt).getNegativePrefix();
37432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ((DecimalFormat)fmt).setNegativePrefix(SUPPRESS_NEGATIVE_PREFIX);
37442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                number = fmt.parse(text, pos);
37452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ((DecimalFormat)fmt).setNegativePrefix(oldPrefix);
37462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
37472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                boolean dateNumberFormat = (fmt instanceof DateNumberFormat);
37482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (dateNumberFormat) {
37492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ((DateNumberFormat)fmt).setParsePositiveOnly(true);
37502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
37512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                number = fmt.parse(text, pos);
37522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (dateNumberFormat) {
37532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ((DateNumberFormat)fmt).setParsePositiveOnly(false);
37542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
37552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
37562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
37572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (maxDigits > 0) {
37582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // adjust the result to fit into
37592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // the maxDigits and move the position back
37602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int nDigits = pos.getIndex() - oldPos;
37612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (nDigits > maxDigits) {
37622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                double val = number.doubleValue();
37632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                nDigits -= maxDigits;
37642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                while (nDigits > 0) {
37652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    val /= 10;
37662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    nDigits--;
37672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
37682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                pos.setIndex(oldPos + maxDigits);
37692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                number = Integer.valueOf((int)val);
37702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
37712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
37722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return number;
37732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
37742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
37752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
37762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
37772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Translate a pattern, mapping each character in the from string to the
37782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * corresponding character in the to string.
37792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
37802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private String translatePattern(String pat, String from, String to) {
37812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        StringBuilder result = new StringBuilder();
37822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean inQuote = false;
37832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = 0; i < pat.length(); ++i) {
37842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            char c = pat.charAt(i);
37852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (inQuote) {
37862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (c == '\'')
37872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    inQuote = false;
37882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
37892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (c == '\'') {
37902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    inQuote = true;
37912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else if (isSyntaxChar(c)) {
37922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int ci = from.indexOf(c);
37932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (ci != -1) {
37942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        c = to.charAt(ci);
37952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
37962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // do not worry on translatepattern if the character is not listed
37972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // we do the validity check elsewhere
37982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
37992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
38002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            result.append(c);
38012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
38022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (inQuote) {
38032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("Unfinished quote in pattern");
38042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
38052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return result.toString();
38062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
38072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
38082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
38092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Return a pattern string describing this date format.
38102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
38112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public String toPattern() {
38122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return pattern;
38132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
38142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
38152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
38162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Return a localized pattern string describing this date format.
3817f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * <p>
3818f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * <b>Note:</b> This implementation depends on {@link DateFormatSymbols#getLocalPatternChars()}
3819f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * to get localized format pattern characters. ICU does not include
3820f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * localized pattern character data, therefore, unless user sets localized
3821f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * pattern characters manually, this method returns the same result as
3822f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * {@link #toPattern()}.
38232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
38242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public String toLocalizedPattern() {
38252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return translatePattern(pattern,
38262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                DateFormatSymbols.patternChars,
38272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                formatData.localPatternChars);
38282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
38292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
38302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
38312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Apply the given unlocalized pattern string to this date format.
38322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
38332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void applyPattern(String pat)
38342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
38352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.pattern = pat;
38361c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        parsePattern();
38371c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
38382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        setLocale(null, null);
38392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // reset parsed pattern items
38402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        patternItems = null;
38412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
38422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
38432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
38442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Apply the given localized pattern string to this date format.
38452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
38462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void applyLocalizedPattern(String pat) {
38472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.pattern = translatePattern(pat,
38482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                        formatData.localPatternChars,
38492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                        DateFormatSymbols.patternChars);
38502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        setLocale(null, null);
38512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
38522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
38532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
38542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Gets the date/time formatting data.
38552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return a copy of the date-time formatting data associated
38562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * with this date-time formatter.
38572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
38582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public DateFormatSymbols getDateFormatSymbols()
38592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
38602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return (DateFormatSymbols)formatData.clone();
38612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
38622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
38632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
38642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Allows you to set the date/time formatting data.
38652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param newFormatSymbols the new symbols
38662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
38672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void setDateFormatSymbols(DateFormatSymbols newFormatSymbols)
38682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
38692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.formatData = (DateFormatSymbols)newFormatSymbols.clone();
38702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
38712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
38722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
38732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Method for subclasses to access the DateFormatSymbols.
38742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
38752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    protected DateFormatSymbols getSymbols() {
38762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return formatData;
38772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
38782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
38792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
38801537b2f39245c07b00aa78c3600f7aebcb172490Neil Fuller     * <strong>[icu]</strong> Gets the time zone formatter which this date/time
38812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * formatter uses to format and parse a time zone.
38821c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert     *
38832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the time zone formatter which this date/time
38842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * formatter uses.
38852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
38862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public TimeZoneFormat getTimeZoneFormat() {
38872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return tzFormat().freeze();
38882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
38892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
38902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
38911537b2f39245c07b00aa78c3600f7aebcb172490Neil Fuller     * <strong>[icu]</strong> Allows you to set the time zone formatter.
38921c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert     *
38932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param tzfmt the new time zone formatter
38942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
38952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void setTimeZoneFormat(TimeZoneFormat tzfmt) {
38962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (tzfmt.isFrozen()) {
38972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // If frozen, use it as is.
38982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            tzFormat = tzfmt;
38992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
39002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // If not frozen, clone and freeze.
39012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            tzFormat = tzfmt.cloneAsThawed().freeze();
39022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
39032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
39042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
39052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
39062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Overrides Cloneable
39072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3908f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    @Override
39092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Object clone() {
39102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        SimpleDateFormat other = (SimpleDateFormat) super.clone();
39112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        other.formatData = (DateFormatSymbols) formatData.clone();
39122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // We must create a new copy of work buffer used by
39132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // the fast numeric field format code.
39142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (this.decimalBuf != null) {
39152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            other.decimalBuf = new char[DECIMAL_BUF_SIZE];
39162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
39172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return other;
39182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
39192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
39202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
39212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Override hashCode.
39222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Generates the hash code for the SimpleDateFormat object
39232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3924f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    @Override
39252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int hashCode()
39262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
39272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return pattern.hashCode();
39282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // just enough fields for a reasonable distribution
39292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
39302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
39312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
39322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Override equals.
39332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3934f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    @Override
39352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public boolean equals(Object obj)
39362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
39372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (!super.equals(obj)) return false; // super does class check
39382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        SimpleDateFormat that = (SimpleDateFormat) obj;
39392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return (pattern.equals(that.pattern)
39402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                && formatData.equals(that.formatData));
39412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
39422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
39432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
39442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Override writeObject.
39452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * See http://docs.oracle.com/javase/6/docs/api/java/io/ObjectOutputStream.html
39462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
39472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void writeObject(ObjectOutputStream stream) throws IOException{
39482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (defaultCenturyStart == null) {
39492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // if defaultCenturyStart is not yet initialized,
39502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // calculate and set value before serialization.
39512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            initializeDefaultCenturyStart(defaultCenturyBase);
39522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
39532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        initializeTimeZoneFormat(false);
39542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        stream.defaultWriteObject();
39552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        stream.writeInt(getContext(DisplayContext.Type.CAPITALIZATION).value());
39562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
39572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
39582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
39592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Override readObject.
39602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * See http://docs.oracle.com/javase/6/docs/api/java/io/ObjectInputStream.html
39612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
39622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void readObject(ObjectInputStream stream)
39632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        throws IOException, ClassNotFoundException {
39642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        stream.defaultReadObject();
39652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int capitalizationSettingValue = (serialVersionOnStream > 1)? stream.readInt(): -1;
39662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        ///CLOVER:OFF
39672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // don't have old serial data to test with
39682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (serialVersionOnStream < 1) {
39692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // didn't have defaultCenturyStart field
39702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            defaultCenturyBase = System.currentTimeMillis();
39712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
39722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        ///CLOVER:ON
39732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        else {
39742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // fill in dependent transient field
39752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            parseAmbiguousDatesAsAfter(defaultCenturyStart);
39762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
39772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        serialVersionOnStream = currentSerialVersion;
39782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        locale = getLocale(ULocale.VALID_LOCALE);
39792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (locale == null) {
39802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // ICU4J 3.6 or older versions did not have UFormat locales
39812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // in the serialized data. This is just for preventing the
39822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // worst case scenario...
39832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            locale = ULocale.getDefault(Category.FORMAT);
39842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
39852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
39862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        initLocalZeroPaddingNumberFormat();
39872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
39882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        setContext(DisplayContext.CAPITALIZATION_NONE);
39892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (capitalizationSettingValue >= 0) {
39902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (DisplayContext context: DisplayContext.values()) {
39912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (context.value() == capitalizationSettingValue) {
39922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    setContext(context);
39932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
39942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
39952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
39962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
39971c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
39982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // if serialized pre-56 update & turned off partial match switch to new enum value
39992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_PARTIAL_MATCH) == false) {
40002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            setBooleanAttribute(DateFormat.BooleanAttribute.PARSE_PARTIAL_LITERAL_MATCH, false);
40012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
40021c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
40031c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        parsePattern();
40042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
40052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
40062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
40072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Format the object to an attributed string, and return the corresponding iterator
40082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Overrides superclass method.
40092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
40102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param obj The object to format
40112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return <code>AttributedCharacterIterator</code> describing the formatted value.
40122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4013f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    @Override
40142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
40152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Calendar cal = calendar;
40162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (obj instanceof Calendar) {
40172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            cal = (Calendar)obj;
40182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if (obj instanceof Date) {
40192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            calendar.setTime((Date)obj);
40202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if (obj instanceof Number) {
40212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            calendar.setTimeInMillis(((Number)obj).longValue());
40222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
40232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("Cannot format given Object as a Date");
40242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
40252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        StringBuffer toAppendTo = new StringBuffer();
40262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        FieldPosition pos = new FieldPosition(0);
40272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        List<FieldPosition> attributes = new ArrayList<FieldPosition>();
40282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        format(cal, getContext(DisplayContext.Type.CAPITALIZATION), toAppendTo, pos, attributes);
40292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
40302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        AttributedString as = new AttributedString(toAppendTo.toString());
40312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
40322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // add DateFormat field attributes to the AttributedString
40332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = 0; i < attributes.size(); i++) {
40342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            FieldPosition fp = attributes.get(i);
40352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            Format.Field attribute = fp.getFieldAttribute();
40362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            as.addAttribute(attribute, attribute, fp.getBeginIndex(), fp.getEndIndex());
40372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
40382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // return the CharacterIterator from AttributedString
40392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return as.getIterator();
40402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
40412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
40422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
40432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the locale of this simple date formatter.
40442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * It is package accessible. also used in DateIntervalFormat.
40452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
40462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return   locale in this simple date formatter
40472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
40482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    ULocale getLocale()
40492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
40502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return locale;
40512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
40522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
40532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
40542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
40552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
40562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Check whether the 'field' is smaller than all the fields covered in
40572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * pattern, return true if it is.
40582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The sequence of calendar field,
40592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * from large to small is: ERA, YEAR, MONTH, DATE, AM_PM, HOUR, MINUTE,...
40602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param field    the calendar field need to check against
40612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return         true if the 'field' is smaller than all the fields
40622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                 covered in pattern. false otherwise.
40632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
40642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
40652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    boolean isFieldUnitIgnored(int field) {
40662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return isFieldUnitIgnored(pattern, field);
40672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
40682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
40692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
40702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
40712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Check whether the 'field' is smaller than all the fields covered in
40722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * pattern, return true if it is.
40732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The sequence of calendar field,
40742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * from large to small is: ERA, YEAR, MONTH, DATE, AM_PM, HOUR, MINUTE,...
40752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param pattern  the pattern to check against
40762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param field    the calendar field need to check against
40772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return         true if the 'field' is smaller than all the fields
40782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                 covered in pattern. false otherwise.
40792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
40802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static boolean isFieldUnitIgnored(String pattern, int field) {
40812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int fieldLevel = CALENDAR_FIELD_TO_LEVEL[field];
40822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int level;
40832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        char ch;
40842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean inQuote = false;
40852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        char prevCh = 0;
40862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int count = 0;
40872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
40882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = 0; i < pattern.length(); ++i) {
40892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            ch = pattern.charAt(i);
40902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (ch != prevCh && count > 0) {
40912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                level = getLevelFromChar(prevCh);
40922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (fieldLevel <= level) {
40932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return false;
40942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
40952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                count = 0;
40962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
40972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (ch == '\'') {
40982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ((i+1) < pattern.length() && pattern.charAt(i+1) == '\'') {
40992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ++i;
41002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
41012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    inQuote = ! inQuote;
41022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
41032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (!inQuote && isSyntaxChar(ch)) {
41042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                prevCh = ch;
41052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ++count;
41062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
41072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
41082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (count > 0) {
41092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // last item
41102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            level = getLevelFromChar(prevCh);
41112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (fieldLevel <= level) {
41122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return false;
41132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
41142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
41152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return true;
41162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
41172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
41182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
41192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
41202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Format date interval by algorithm.
41212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * It is supposed to be used only by CLDR survey tool.
41222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
41232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param fromCalendar      calendar set to the from date in date interval
41242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          to be formatted into date interval stirng
41252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param toCalendar        calendar set to the to date in date interval
41262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          to be formatted into date interval stirng
41272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param appendTo          Output parameter to receive result.
41282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          Result is appended to existing contents.
41292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param pos               On input: an alignment field, if desired.
41302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          On output: the offsets of the alignment field.
41312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @exception IllegalArgumentException when there is non-recognized
41322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                                     pattern letter
41332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return                  Reference to 'appendTo' parameter.
41342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @deprecated This API is ICU internal only.
413593cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller     * @hide original deprecated declaration
4136836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller     * @hide draft / provisional / internal are hidden on Android
41372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
41382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Deprecated
41392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public final StringBuffer intervalFormatByAlgorithm(Calendar fromCalendar,
41402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                        Calendar toCalendar,
41412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                        StringBuffer appendTo,
41422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                        FieldPosition pos)
41432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                              throws IllegalArgumentException
41442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
41452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // not support different calendar types and time zones
41462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( !fromCalendar.isEquivalentTo(toCalendar) ) {
41472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("can not format on two different calendars");
41482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
41492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
41502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Object[] items = getPatternItems();
41512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int diffBegin = -1;
41522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int diffEnd = -1;
41532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
41542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* look for different formatting string range */
41552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // look for start of difference
41562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        try {
41572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (int i = 0; i < items.length; i++) {
41582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ( diffCalFieldValue(fromCalendar, toCalendar, items, i) ) {
41592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    diffBegin = i;
41602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
41612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
41622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
41632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
41642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( diffBegin == -1 ) {
41652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // no difference, single date format
41662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return format(fromCalendar, appendTo, pos);
41672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
41682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
41692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // look for end of difference
41702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (int i = items.length-1; i >= diffBegin; i--) {
41712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ( diffCalFieldValue(fromCalendar, toCalendar, items, i) ) {
41722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    diffEnd = i;
41732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
41742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
41752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
41762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } catch ( IllegalArgumentException e ) {
41772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException(e.toString());
41782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
41792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
41802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // full range is different
41812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( diffBegin == 0 && diffEnd == items.length-1 ) {
41822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            format(fromCalendar, appendTo, pos);
41832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            appendTo.append(" \u2013 "); // default separator
41842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            format(toCalendar, appendTo, pos);
41852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return appendTo;
41862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
41872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
41882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
41892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* search for largest calendar field within the different range */
41902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int highestLevel = 1000;
41912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = diffBegin; i <= diffEnd; i++) {
41922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( items[i] instanceof String) {
41932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                continue;
41942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
41952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            PatternItem item = (PatternItem)items[i];
41962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            char ch = item.type;
41972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int patternCharIndex = getIndexFromChar(ch);
41982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (patternCharIndex == -1) {
41992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                throw new IllegalArgumentException("Illegal pattern character " +
42002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                   "'" + ch + "' in \"" +
42012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                   pattern + '"');
42022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
42032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
42042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( patternCharIndex < highestLevel ) {
42052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                highestLevel = patternCharIndex;
42062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
42072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
42082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
42092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* re-calculate diff range, including those calendar field which
42102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           is in lower level than the largest calendar field covered
42112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller           in diff range calculated. */
42122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        try {
42132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (int i = 0; i < diffBegin; i++) {
42142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ( lowerLevel(items, i, highestLevel) ) {
42152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    diffBegin = i;
42162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
42172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
42182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
42192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
42202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
42212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (int i = items.length-1; i > diffEnd; i--) {
42222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ( lowerLevel(items, i, highestLevel) ) {
42232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    diffEnd = i;
42242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    break;
42252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
42262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
42272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } catch ( IllegalArgumentException e ) {
42282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException(e.toString());
42292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
42302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
42312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
42322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // full range is different
42332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( diffBegin == 0 && diffEnd == items.length-1 ) {
42342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            format(fromCalendar, appendTo, pos);
42352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            appendTo.append(" \u2013 "); // default separator
42362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            format(toCalendar, appendTo, pos);
42372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return appendTo;
42382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
42392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
42402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
42412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // formatting
42422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Initialize
42432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pos.setBeginIndex(0);
42442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        pos.setEndIndex(0);
42452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        DisplayContext capSetting = getContext(DisplayContext.Type.CAPITALIZATION);
42462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
42472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // formatting date 1
42482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = 0; i <= diffEnd; i++) {
42492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (items[i] instanceof String) {
42502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                appendTo.append((String)items[i]);
42512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
42522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                PatternItem item = (PatternItem)items[i];
42532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (useFastFormat) {
42542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    subFormat(appendTo, item.type, item.length, appendTo.length(),
42552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                              i, capSetting, pos, fromCalendar);
42562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
42572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    appendTo.append(subFormat(item.type, item.length, appendTo.length(),
42582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                              i, capSetting, pos, fromCalendar));
42592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
42602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
42612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
42622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
42632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        appendTo.append(" \u2013 "); // default separator
42642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
42652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // formatting date 2
42662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = diffBegin; i < items.length; i++) {
42672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (items[i] instanceof String) {
42682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                appendTo.append((String)items[i]);
42692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
42702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                PatternItem item = (PatternItem)items[i];
42712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (useFastFormat) {
42722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    subFormat(appendTo, item.type, item.length, appendTo.length(),
42732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                              i, capSetting, pos, toCalendar);
42742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
42752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    appendTo.append(subFormat(item.type, item.length, appendTo.length(),
42762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                              i, capSetting, pos, toCalendar));
42772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
42782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
42792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
42802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return appendTo;
42812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
42822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
42832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
42842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
42852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * check whether the i-th item in 2 calendar is in different value.
42862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
42872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * It is supposed to be used only by CLDR survey tool.
42882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * It is used by intervalFormatByAlgorithm().
42892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
42902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param fromCalendar   one calendar
42912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param toCalendar     the other calendar
42922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param items          pattern items
42932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param i              the i-th item in pattern items
42942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @exception IllegalArgumentException when there is non-recognized
42952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                                     pattern letter
42962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return               true is i-th item in 2 calendar is in different
42972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                       value, false otherwise.
42982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
42992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private boolean diffCalFieldValue(Calendar fromCalendar,
43002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                      Calendar toCalendar,
43012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                      Object[] items,
43022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                      int i) throws IllegalArgumentException {
43032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( items[i] instanceof String) {
43042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return false;
43052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
43062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        PatternItem item = (PatternItem)items[i];
43072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        char ch = item.type;
43082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int patternCharIndex = getIndexFromChar(ch);
43092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (patternCharIndex == -1) {
43102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("Illegal pattern character " +
43112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                               "'" + ch + "' in \"" +
43122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                               pattern + '"');
43132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
43142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
43152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        final int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
43162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (field >= 0) {
43172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int value = fromCalendar.get(field);
43182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int value_2 = toCalendar.get(field);
43192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( value != value_2 ) {
43202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return true;
43212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
43222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
43232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return false;
43242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
43252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
43262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
43272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
43282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * check whether the i-th item's level is lower than the input 'level'
43292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
43302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * It is supposed to be used only by CLDR survey tool.
43312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * It is used by intervalFormatByAlgorithm().
43322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
43332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param items  the pattern items
43342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param i      the i-th item in pattern items
43352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param level  the level with which the i-th pattern item compared to
43362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @exception IllegalArgumentException when there is non-recognized
43372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                                     pattern letter
43382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return       true if i-th pattern item is lower than 'level',
43392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *               false otherwise
43402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
43412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private boolean lowerLevel(Object[] items, int i, int level)
43422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    throws IllegalArgumentException {
43432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (items[i] instanceof String) {
43442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return false;
43452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
43462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        PatternItem item = (PatternItem)items[i];
43472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        char ch = item.type;
43482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int patternCharIndex = getLevelFromChar(ch);
43492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (patternCharIndex == -1) {
43502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("Illegal pattern character " +
43512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                               "'" + ch + "' in \"" +
43522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                               pattern + '"');
43532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
43542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
43552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (patternCharIndex >= level) {
43562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return true;
43572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
43582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return false;
43592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
43602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
43612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
43622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * allow the user to set the NumberFormat for several fields
43632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * It can be a single field like: "y"(year) or "M"(month)
43642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * It can be several field combined together: "yMd"(year, month and date)
43651c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert     * Note:
43662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 1 symbol field is enough for multiple symbol fields (so "y" will override "yy", "yyy")
43672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If the field is not numeric, then override has no effect (like "MMM" will use abbreviation, not numerical field)
43681c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert     *
43692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param fields the fields to override
43701c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert     * @param overrideNF the NumbeferFormat used
43712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @exception IllegalArgumentException when the fields contain invalid field
43722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
43732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void setNumberFormat(String fields, NumberFormat overrideNF) {
43742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        overrideNF.setGroupingUsed(false);
43752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String nsName = "$" + UUID.randomUUID().toString();
43761c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
43772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // initialize mapping if not there
43782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (numberFormatters == null) {
43792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            numberFormatters = new HashMap<String, NumberFormat>();
43802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
43812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (overrideMap == null) {
43822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            overrideMap = new HashMap<Character, String>();
43832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
43842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
43852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // separate string into char and add to maps
43862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = 0; i < fields.length(); i++) {
43872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            char field = fields.charAt(i);
43882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (DateFormatSymbols.patternChars.indexOf(field) == -1) {
43892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                throw new IllegalArgumentException("Illegal field character " + "'" + field + "' in setNumberFormat.");
43902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
43912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            overrideMap.put(field, nsName);
43922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            numberFormatters.put(nsName, overrideNF);
43932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
43942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
43952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Since one or more of the override number formatters might be complex,
43962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // we can't rely on the fast numfmt where we have a partial field override.
43972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        useLocalZeroPaddingNumberFormat = false;
43982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
43991c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
44002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
44012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * give the NumberFormat used for the field like 'y'(year) and 'M'(year)
44022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
44032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param field the field the user wants
44042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return override NumberFormat used for the field
44052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
44062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public NumberFormat getNumberFormat(char field) {
44072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Character ovrField;
44082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        ovrField = Character.valueOf(field);
44092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (overrideMap != null && overrideMap.containsKey(ovrField)) {
44102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String nsName = overrideMap.get(ovrField).toString();
44112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            NumberFormat nf = numberFormatters.get(nsName);
44122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return nf;
44132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
44142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return numberFormat;
44152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
44162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
44172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
44182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void initNumberFormatters(ULocale loc) {
44192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
44202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       numberFormatters = new HashMap<String, NumberFormat>();
44212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       overrideMap = new HashMap<Character, String>();
44222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       processOverrideString(loc,override);
44232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
44242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
44252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
44262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void processOverrideString(ULocale loc, String str) {
44272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
44282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( str == null || str.length() == 0 )
44292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
44302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
44312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int start = 0;
44322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int end;
44332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String nsName;
44342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Character ovrField;
44352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean moreToProcess = true;
44362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean fullOverride;
44372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
44382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        while (moreToProcess) {
44392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int delimiterPosition = str.indexOf(";",start);
44402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (delimiterPosition == -1) {
44412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                moreToProcess = false;
44422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                end = str.length();
44432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
44442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                end = delimiterPosition;
44452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
44462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
44472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String currentString = str.substring(start,end);
44482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int equalSignPosition = currentString.indexOf("=");
44492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (equalSignPosition == -1) { // Simple override string such as "hebrew"
44502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               nsName = currentString;
44512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               fullOverride = true;
44522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else { // Field specific override string such as "y=hebrew"
44532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               nsName = currentString.substring(equalSignPosition+1);
44542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               ovrField = Character.valueOf(currentString.charAt(0));
44552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               overrideMap.put(ovrField,nsName);
44562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller               fullOverride = false;
44572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
44582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
44592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            ULocale ovrLoc = new ULocale(loc.getBaseName()+"@numbers="+nsName);
44602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            NumberFormat nf = NumberFormat.createInstance(ovrLoc,NumberFormat.NUMBERSTYLE);
44612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            nf.setGroupingUsed(false);
44621c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
44632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (fullOverride) {
44642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                setNumberFormat(nf);
44652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
44662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Since one or more of the override number formatters might be complex,
44672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // we can't rely on the fast numfmt where we have a partial field override.
44682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                useLocalZeroPaddingNumberFormat = false;
44692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
44702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
44712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (!fullOverride && !numberFormatters.containsKey(nsName)) {
44722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                  numberFormatters.put(nsName,nf);
44732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
44742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
44752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            start = delimiterPosition + 1;
44762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
44772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
44781c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
44791c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert    private void parsePattern() {
44801c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        hasMinute = false;
44811c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        hasSecond = false;
44821c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert
44831c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        boolean inQuote = false;
44841c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        for (int i = 0; i < pattern.length(); ++i) {
44851c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            char ch = pattern.charAt(i);
44861c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            if (ch == '\'') {
44871c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                inQuote = !inQuote;
44881c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            }
44891c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            if (!inQuote) {
44901c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                if (ch == 'm') {
44911c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    hasMinute = true;
44921c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                }
44931c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                if (ch == 's') {
44941c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                    hasSecond = true;
44951c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert                }
44961c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert            }
44971c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert        }
44981c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert    }
44992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller}
4500