17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/*
27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *******************************************************************************
3f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * Copyright (C) 1996-2015, International Business Machines Corporation and
4f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * others. All Rights Reserved.
57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *******************************************************************************
67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */
77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.text;
97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.IOException;
117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.ObjectInputStream;
127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.ObjectOutputStream;
137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.text.AttributedCharacterIterator;
147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.text.AttributedString;
157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.text.FieldPosition;
167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.text.Format;
177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.text.ParsePosition;
187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.ArrayList;
197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Date;
207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.HashMap;
217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.List;
227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Locale;
237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.MissingResourceException;
247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.UUID;
257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.CalendarData;
277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.DateNumberFormat;
287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.ICUCache;
297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.PatternProps;
307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.SimpleCache;
317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.lang.UCharacter;
327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.TimeZoneFormat.Style;
337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.TimeZoneFormat.TimeType;
347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.BasicTimeZone;
357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.Calendar;
367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.HebrewCalendar;
377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.Output;
387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.TimeZone;
397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.TimeZoneTransition;
407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ULocale;
417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ULocale.Category;
427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/**
457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icuenhanced java.text.SimpleDateFormat}.{@icu _usage_}
467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p><code>SimpleDateFormat</code> is a concrete class for formatting and
487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * parsing dates in a locale-sensitive manner. It allows for formatting
49bee65486a185907111f3be60992433e133ec0e32Scott Russell * (date -&gt; text), parsing (text -&gt; date), and normalization.
507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>
527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>SimpleDateFormat</code> allows you to start by choosing
537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * any user-defined patterns for date-time formatting. However, you
547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * are encouraged to create a date-time formatter with either
557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>getTimeInstance</code>, <code>getDateInstance</code>, or
567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>getDateTimeInstance</code> in <code>DateFormat</code>. Each
577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * of these class methods can return a date/time formatter initialized
587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * with a default format pattern. You may modify the format pattern
597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * using the <code>applyPattern</code> methods as desired.
607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * For more information on using these methods, see
617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@link DateFormat}.
627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p><strong>Date and Time Patterns:</strong></p>
647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Date and time formats are specified by <em>date and time pattern</em> strings.
667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Within date and time pattern strings, all unquoted ASCII letters [A-Za-z] are reserved
677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * as pattern letters representing calendar fields. <code>SimpleDateFormat</code> supports
687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the date and time formatting algorithm and pattern letters defined by <a href="http://www.unicode.org/reports/tr35/">UTS#35
697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Unicode Locale Data Markup Language (LDML)</a>. The following pattern letters are
707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * currently available (note that the actual values depend on CLDR and may change from the
717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * examples shown here):</p>
727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <blockquote>
737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <table border="1">
747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <th>Field</th>
767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <th style="text-align: center">Sym.</th>
777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <th style="text-align: center">No.</th>
787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <th>Example</th>
797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <th>Description</th>
807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <th rowspan="3">era</th>
837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center" rowspan="3">G</td>
847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..3</td>
857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>AD</td>
867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="3">Era - Replaced with the Era string for the current date. One to three letters for the
877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         abbreviated form, four letters for the long (wide) form, five for the narrow form.</td>
887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">4</td>
917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Anno Domini</td>
927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">5</td>
957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>A</td>
967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <th rowspan="6">year</th>
997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">y</td>
1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..n</td>
1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>1996</td>
1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Year. Normally the length specifies the padding, but for two letters it also specifies the maximum
103bee65486a185907111f3be60992433e133ec0e32Scott Russell *         length. Example:<div style="text-align: center">
1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *             <center>
1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *             <table border="1" cellpadding="2" cellspacing="0">
1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                 <tr>
1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <th>Year</th>
1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <th style="text-align: right">y</th>
1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <th style="text-align: right">yy</th>
1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <th style="text-align: right">yyy</th>
1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <th style="text-align: right">yyyy</th>
1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <th style="text-align: right">yyyyy</th>
1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                 </tr>
1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                 <tr>
1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td>AD 1</td>
1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">1</td>
1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">01</td>
1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">001</td>
1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">0001</td>
1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">00001</td>
1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                 </tr>
1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                 <tr>
1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td>AD 12</td>
1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">12</td>
1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">12</td>
1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">012</td>
1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">0012</td>
1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">00012</td>
1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                 </tr>
1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                 <tr>
1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td>AD 123</td>
1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">123</td>
1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">23</td>
1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">123</td>
1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">0123</td>
1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">00123</td>
1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                 </tr>
1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                 <tr>
1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td>AD 1234</td>
1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">1234</td>
1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">34</td>
1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">1234</td>
1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">1234</td>
1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">01234</td>
1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                 </tr>
1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                 <tr>
1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td>AD 12345</td>
1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">12345</td>
1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">45</td>
1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">12345</td>
1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">12345</td>
1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                     <td style="text-align: right">12345</td>
1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *                 </tr>
1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *             </table>
1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *             </center></div>
1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         </td>
1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">Y</td>
1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..n</td>
1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>1997</td>
1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Year (in "Week of Year" based calendars). Normally the length specifies the padding,
1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         but for two letters it also specifies the maximum length. This year designation is used in ISO
1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         year-week calendar as defined by ISO 8601, but can be used in non-Gregorian based calendar systems
1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         where week date processing is desired. May not always be the same value as calendar year.</td>
1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">u</td>
1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..n</td>
1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>4601</td>
1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Extended year. This is a single number designating the year of this calendar system, encompassing
1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         all supra-year fields. For example, for the Julian calendar system, year numbers are positive, with an
1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         era of BCE or CE. An extended year value for the Julian calendar system assigns positive values to CE
1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         years and negative values to BCE years, with 1 BCE being year 0.</td>
1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center" rowspan="3">U</td>
1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..3</td>
1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>甲子</td>
1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="3">Cyclic year name. Calendars such as the Chinese lunar calendar (and related calendars)
1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         and the Hindu calendars use 60-year cycles of year names. Use one through three letters for the abbreviated
1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         name, four for the full (wide) name, or five for the narrow name (currently the data only provides abbreviated names,
1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         which will be used for all requested name widths). If the calendar does not provide cyclic year name data,
1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         or if the year value to be formatted is out of the range of years for which cyclic name data is provided,
1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         then numeric formatting is used (behaves like 'y').</td>
1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">4</td>
1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>(currently also 甲子)</td>
1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">5</td>
1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>(currently also 甲子)</td>
1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <th rowspan="6">quarter</th>
1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="3" style="text-align: center">Q</td>
1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..2</td>
1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>02</td>
2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="3">Quarter - Use one or two for the numerical quarter, three for the abbreviation, or four
2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         for the full (wide) name (five for the narrow name is not yet supported).</td>
2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">3</td>
2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Q2</td>
2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">4</td>
2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>2nd quarter</td>
2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="3" style="text-align: center">q</td>
2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..2</td>
2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>02</td>
2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="3"><b>Stand-Alone</b> Quarter - Use one or two for the numerical quarter, three for the abbreviation,
2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         or four for the full name (five for the narrow name is not yet supported).</td>
2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">3</td>
2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Q2</td>
2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">4</td>
2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>2nd quarter</td>
2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <th rowspan="8">month</th>
2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="4" style="text-align: center">M</td>
2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..2</td>
2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>09</td>
2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="4">Month - Use one or two for the numerical month, three for the abbreviation, four for
2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         the full (wide) name, or five for the narrow name. With two ("MM"), the month number is zero-padded
2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         if necessary (e.g. "08").</td>
2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">3</td>
2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Sep</td>
2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">4</td>
2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>September</td>
2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">5</td>
2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>S</td>
2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="4" style="text-align: center">L</td>
2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..2</td>
2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>09</td>
2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="4"><b>Stand-Alone</b> Month - Use one or two for the numerical month, three for the abbreviation,
2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         four for the full (wide) name, or 5 for the narrow name. With two ("LL"), the month number is zero-padded if
2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         necessary (e.g. "08").</td>
2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">3</td>
2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Sep</td>
2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">4</td>
2617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>September</td>
2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">5</td>
2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>S</td>
2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <th rowspan="2">week</th>
2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">w</td>
2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..2</td>
2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>27</td>
2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Week of Year. Use "w" to show the minimum number of digits, or "ww" to always show two digits
2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         (zero-padding if necessary, e.g. "08").</td>
2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">W</td>
2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1</td>
2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>3</td>
2797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Week of Month</td>
2807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
2817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
2827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <th rowspan="4">day</th>
2837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">d</td>
2847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..2</td>
2857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>1</td>
2867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Date - Day of the month. Use "d" to show the minimum number of digits, or "dd" to always show
2877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         two digits (zero-padding if necessary, e.g. "08").</td>
2887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
2897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
2907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">D</td>
2917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..3</td>
2927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>345</td>
2937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Day of year</td>
2947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
2957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
2967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">F</td>
2977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1</td>
2987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>2</td>
2997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Day of Week in Month. The example is for the 2nd Wed in July</td>
3007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
3017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
3027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">g</td>
3037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..n</td>
3047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>2451334</td>
3057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Modified Julian day. This is different from the conventional Julian day number in two regards.
3067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         First, it demarcates days at local zone midnight, rather than noon GMT. Second, it is a local number;
3077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         that is, it depends on the local time zone. It can be thought of as a single number that encompasses
3087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         all the date-related fields.</td>
3097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
3107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
3117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <th rowspan="14">week<br>
3127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         day</th>
3137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="4" style="text-align: center">E</td>
3147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..3</td>
3157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Tue</td>
3167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="4">Day of week - Use one through three letters for the short day, four for the full (wide) name,
3177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         five for the narrow name, or six for the short name.</td>
3187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
3197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
3207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">4</td>
3217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Tuesday</td>
3227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
3237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
3247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">5</td>
3257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>T</td>
3267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
3277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
3287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">6</td>
3297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Tu</td>
3307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
3317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
3327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="5" style="text-align: center">e</td>
3337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..2</td>
3347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>2</td>
3357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="5">Local day of week. Same as E except adds a numeric value that will depend on the local
3367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         starting day of the week, using one or two letters. For this example, Monday is the first day of the week.</td>
3377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
3387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
3397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">3</td>
3407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Tue</td>
3417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
3427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
3437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">4</td>
3447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Tuesday</td>
3457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
3467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
3477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">5</td>
3487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>T</td>
3497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
3507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
3517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">6</td>
3527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Tu</td>
3537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
3547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
3557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="5" style="text-align: center">c</td>
3567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1</td>
3577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>2</td>
3587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="5"><b>Stand-Alone</b> local day of week - Use one letter for the local numeric value (same
3597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         as 'e'), three for the short day, four for the full (wide) name, five for the narrow name, or six for
3607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         the short name.</td>
3617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
3627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
3637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">3</td>
3647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Tue</td>
3657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
3667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
3677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">4</td>
3687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Tuesday</td>
3697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
3707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
3717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">5</td>
3727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>T</td>
3737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
3747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
3757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">6</td>
3767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Tu</td>
3777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
3787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
3797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <th>period</th>
3807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">a</td>
3817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1</td>
3827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>AM</td>
3837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>AM or PM</td>
3847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
3857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
3867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <th rowspan="4">hour</th>
3877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">h</td>
3887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..2</td>
3897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>11</td>
3907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Hour [1-12]. When used in skeleton data or in a skeleton passed in an API for flexible data pattern
3917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         generation, it should match the 12-hour-cycle format preferred by the locale (h or K); it should not match
3927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         a 24-hour-cycle format (H or k). Use hh for zero padding.</td>
3937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
3947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
3957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">H</td>
3967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..2</td>
3977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>13</td>
3987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Hour [0-23]. When used in skeleton data or in a skeleton passed in an API for flexible data pattern
3997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         generation, it should match the 24-hour-cycle format preferred by the locale (H or k); it should not match a
4007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         12-hour-cycle format (h or K). Use HH for zero padding.</td>
4017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
4027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
4037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">K</td>
4047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..2</td>
4057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>0</td>
4067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Hour [0-11]. When used in a skeleton, only matches K or h, see above. Use KK for zero padding.</td>
4077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
4087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
4097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">k</td>
4107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..2</td>
4117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>24</td>
4127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Hour [1-24]. When used in a skeleton, only matches k or H, see above. Use kk for zero padding.</td>
4137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
4147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
4157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <th>minute</th>
4167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">m</td>
4177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..2</td>
4187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>59</td>
4197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Minute. Use "m" to show the minimum number of digits, or "mm" to always show two digits
4207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         (zero-padding if necessary, e.g. "08")..</td>
4217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
4227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
4237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <th rowspan="3">second</th>
4247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">s</td>
4257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..2</td>
4267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>12</td>
4277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Second. Use "s" to show the minimum number of digits, or "ss" to always show two digits
4287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         (zero-padding if necessary, e.g. "08").</td>
4297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
4307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
4317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">S</td>
4327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..n</td>
4337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>3450</td>
4347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <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.
4357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         (example shows display using pattern SSSS for seconds value 12.34567)</td>
4367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
4377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
4387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">A</td>
4397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..n</td>
4407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>69540000</td>
4417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Milliseconds in day. This field behaves <i>exactly</i> like a composite of all time-related fields,
4427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         not including the zone fields. As such, it also reflects discontinuities of those fields on DST transition
4437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         days. On a day of DST onset, it will jump forward. On a day of DST cessation, it will jump backward. This
4447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         reflects the fact that is must be combined with the offset field to obtain a unique local time value.</td>
4457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
4467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
4477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <th rowspan="23">zone</th>
4487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="2" style="text-align: center">z</td>
4497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..3</td>
4507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>PDT</td>
4517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>short specific non-location format</i>.
4527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         Where that is unavailable, falls back to the <i>short localized GMT format</i> ("O").</td>
4537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
4547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
4557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">4</td>
4567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Pacific Daylight Time</td>
4577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>long specific non-location format</i>.
4587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         Where that is unavailable, falls back to the <i>long localized GMT format</i> ("OOOO").</td>
4597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
4607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
4617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="3" style="text-align: center">Z</td>
4627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1..3</td>
4637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>-0800</td>
4647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>ISO8601 basic format</i> with hours, minutes and optional seconds fields.
4657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         The format is equivalent to RFC 822 zone format (when optional seconds field is absent).
4667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         This is equivalent to the "xxxx" specifier.</td>
4677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
4687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
4697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">4</td>
4707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>GMT-8:00</td>
4717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>long localized GMT format</i>.
4727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         This is equivalent to the "OOOO" specifier.</td>
4737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
4747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
4757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">5</td>
4767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>-08:00<br>
4777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         -07:52:58</td>
4787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>ISO8601 extended format</i> with hours, minutes and optional seconds fields.
4797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         The ISO8601 UTC indicator "Z" is used when local time offset is 0.
4807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         This is equivalent to the "XXXXX" specifier.</td>
4817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
4827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
4837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="2" style="text-align: center">O</td>
4847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1</td>
4857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>GMT-8</td>
4867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>short localized GMT format</i>.</td>
4877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
4887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
4897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">4</td>
4907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>GMT-08:00</td>
4917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>long localized GMT format</i>.</td>
4927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
4937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
4947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="2" style="text-align: center">v</td>
4957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1</td>
4967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>PT</td>
4977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>short generic non-location format</i>.
4987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         Where that is unavailable, falls back to the <i>generic location format</i> ("VVVV"),
4997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         then the <i>short localized GMT format</i> as the final fallback.</td>
5007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
5017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
5027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">4</td>
5037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Pacific Time</td>
5047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>long generic non-location format</i>.
5057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         Where that is unavailable, falls back to <i>generic location format</i> ("VVVV").
5067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
5077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
5087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="4" style="text-align: center">V</td>
5097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1</td>
5107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>uslax</td>
5117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The short time zone ID.
5127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         Where that is unavailable, the special short time zone ID <i>unk</i> (Unknown Zone) is used.<br>
5137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <i><b>Note</b>: This specifier was originally used for a variant of the short specific non-location format,
5147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         but it was deprecated in the later version of the LDML specification. In CLDR 23/ICU 51, the definition of
5157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         the specifier was changed to designate a short time zone ID.</i></td>
5167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
5177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
5187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">2</td>
5197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>America/Los_Angeles</td>
5207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The long time zone ID.</td>
5217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
5227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
5237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">3</td>
5247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Los Angeles</td>
5257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The exemplar city (location) for the time zone.
5267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         Where that is unavailable, the localized exemplar city name for the special zone <i>Etc/Unknown</i> is used
5277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         as the fallback (for example, "Unknown City"). </td>
5287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
5297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
5307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">4</td>
5317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>Los Angeles Time</td>
5327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>generic location format</i>.
5337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         Where that is unavailable, falls back to the <i>long localized GMT format</i> ("OOOO";
5347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         Note: Fallback is only necessary with a GMT-style Time Zone ID, like Etc/GMT-830.)<br>
5357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         This is especially useful when presenting possible timezone choices for user selection,
5367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         since the naming is more uniform than the "v" format.</td>
5377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
5387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
5397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="5" style="text-align: center">X</td>
5407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1</td>
5417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>-08<br>
5427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         +0530<br>
5437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         Z</td>
5447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>ISO8601 basic format</i> with hours field and optional minutes field.
5457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         The ISO8601 UTC indicator "Z" is used when local time offset is 0.</td>
5467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
5477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
5487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">2</td>
5497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>-0800<br>
5507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         Z</td>
5517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>ISO8601 basic format</i> with hours and minutes fields.
5527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         The ISO8601 UTC indicator "Z" is used when local time offset is 0.</td>
5537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
5547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
5557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">3</td>
5567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>-08:00<br>
5577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         Z</td>
5587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>ISO8601 extended format</i> with hours and minutes fields.
5597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         The ISO8601 UTC indicator "Z" is used when local time offset is 0.</td>
5607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
5617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
5627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">4</td>
5637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>-0800<br>
5647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         -075258<br>
5657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         Z</td>
5667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>ISO8601 basic format</i> with hours, minutes and optional seconds fields.
5677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         (Note: The seconds field is not supported by the ISO8601 specification.)
5687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         The ISO8601 UTC indicator "Z" is used when local time offset is 0.</td>
5697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
5707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
5717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">5</td>
5727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>-08:00<br>
5737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         -07:52:58<br>
5747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         Z</td>
5757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>ISO8601 extended format</i> with hours, minutes and optional seconds fields.
5767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         (Note: The seconds field is not supported by the ISO8601 specification.)
5777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         The ISO8601 UTC indicator "Z" is used when local time offset is 0.</td>
5787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
5797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
5807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td rowspan="5" style="text-align: center">x</td>
5817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">1</td>
5827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>-08<br>
5837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         +0530</td>
5847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>ISO8601 basic format</i> with hours field and optional minutes field.</td>
5857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
5867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
5877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">2</td>
5887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>-0800</td>
5897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>ISO8601 basic format</i> with hours and minutes fields.</td>
5907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
5917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
5927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">3</td>
5937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>-08:00</td>
5947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>ISO8601 extended format</i> with hours and minutes fields.</td>
5957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
5967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
5977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">4</td>
5987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>-0800<br>
5997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         -075258</td>
6007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>ISO8601 basic format</i> with hours, minutes and optional seconds fields.
6017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         (Note: The seconds field is not supported by the ISO8601 specification.)</td>
6027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
6037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     <tr>
6047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td style="text-align: center">5</td>
6057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>-08:00<br>
6067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         -07:52:58</td>
6077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         <td>The <i>ISO8601 extended format</i> with hours, minutes and optional seconds fields.
6087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *         (Note: The seconds field is not supported by the ISO8601 specification.)</td>
6097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     </tr>
6107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </table>
6117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
6127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </blockquote>
6137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>
6147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Any characters in the pattern that are not in the ranges of ['a'..'z']
6157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and ['A'..'Z'] will be treated as quoted text. For instance, characters
6167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * like ':', '.', ' ', '#' and '@' will appear in the resulting time text
6177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * even they are not embraced within single quotes.
6187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>
6197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A pattern containing any invalid pattern letter will result in a thrown
6207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * exception during formatting or parsing.
6217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
6227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>
6237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <strong>Examples Using the US Locale:</strong>
6247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <blockquote>
6257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <pre>
6267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Format Pattern                         Result
6277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * --------------                         -------
628bee65486a185907111f3be60992433e133ec0e32Scott Russell * "yyyy.MM.dd G 'at' HH:mm:ss vvvv" -&gt;&gt;  1996.07.10 AD at 15:08:56 Pacific Time
629bee65486a185907111f3be60992433e133ec0e32Scott Russell * "EEE, MMM d, ''yy"                -&gt;&gt;  Wed, July 10, '96
630bee65486a185907111f3be60992433e133ec0e32Scott Russell * "h:mm a"                          -&gt;&gt;  12:08 PM
631bee65486a185907111f3be60992433e133ec0e32Scott Russell * "hh 'o''clock' a, zzzz"           -&gt;&gt;  12 o'clock PM, Pacific Daylight Time
632bee65486a185907111f3be60992433e133ec0e32Scott Russell * "K:mm a, vvv"                     -&gt;&gt;  0:00 PM, PT
633bee65486a185907111f3be60992433e133ec0e32Scott Russell * "yyyyy.MMMMM.dd GGG hh:mm aaa"    -&gt;&gt;  01996.July.10 AD 12:08 PM
6347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </pre>
6357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </blockquote>
6367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <strong>Code Sample:</strong>
6377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <blockquote>
6387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <pre>
6397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, "PST");
6407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2*60*60*1000);
6417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*60*60*1000);
6427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <br>
6437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // Format the current time.
6447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * SimpleDateFormat formatter
6457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *     = new SimpleDateFormat ("yyyy.MM.dd G 'at' hh:mm:ss a zzz");
6467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Date currentTime_1 = new Date();
6477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * String dateString = formatter.format(currentTime_1);
6487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <br>
6497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // Parse the previous string back into a Date.
6507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ParsePosition pos = new ParsePosition(0);
6517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Date currentTime_2 = formatter.parse(dateString, pos);
6527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </pre>
6537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </blockquote>
6547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * In the example, the time value <code>currentTime_2</code> obtained from
6557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * parsing will be equal to <code>currentTime_1</code>. However, they may not be
6567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * equal if the am/pm marker 'a' is left out from the format pattern while
6577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the "hour in am/pm" pattern symbol is used. This information loss can
6587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * happen when formatting the time in PM.
6597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
6607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>When parsing a date string using the abbreviated year pattern ("yy"),
6617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * SimpleDateFormat must interpret the abbreviated year
6627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * relative to some century.  It does this by adjusting dates to be
6637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * within 80 years before and 20 years after the time the SimpleDateFormat
6647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * instance is created. For example, using a pattern of "MM/dd/yy" and a
6657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * SimpleDateFormat instance created on Jan 1, 1997,  the string
6667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "01/11/12" would be interpreted as Jan 11, 2012 while the string "05/04/64"
6677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * would be interpreted as May 4, 1964.
6687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * During parsing, only strings consisting of exactly two digits, as defined by
6697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@link com.ibm.icu.lang.UCharacter#isDigit(int)}, will be parsed into the default
6707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * century.
6717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Any other numeric string, such as a one digit string, a three or more digit
6727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * string, or a two digit string that isn't all digits (for example, "-1"), is
6737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * interpreted literally.  So "01/02/3" or "01/02/003" are parsed, using the
6747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * same pattern, as Jan 2, 3 AD.  Likewise, "01/02/-3" is parsed as Jan 2, 4 BC.
6757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
6767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>If the year pattern does not have exactly two 'y' characters, the year is
6777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * interpreted literally, regardless of the number of digits.  So using the
6787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * pattern "MM/dd/yyyy", "01/11/12" parses to Jan 11, 12 A.D.
6797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
6807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>When numeric fields abut one another directly, with no intervening delimiter
6817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * characters, they constitute a run of abutting numeric fields.  Such runs are
6827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * parsed specially.  For example, the format "HHmmss" parses the input text
6837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "123456" to 12:34:56, parses the input text "12345" to 1:23:45, and fails to
6847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * parse "1234".  In other words, the leftmost field of the run is flexible,
6857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * while the others keep a fixed width.  If the parse fails anywhere in the run,
6867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * then the leftmost field is shortened by one character, and the entire run is
6877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * parsed again. This is repeated until either the parse succeeds or the
6887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * leftmost field is one character in length.  If the parse still fails at that
6897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * point, the parse of the run fails.
6907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
6917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>For time zones that have no names, use strings GMT+hours:minutes or
6927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * GMT-hours:minutes.
6937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
6947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>The calendar defines what is the first day of the week, the first week
6957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * of the year, whether hours are zero based or not (0 vs 12 or 24), and the
6967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * time zone. There is one common decimal format to handle all the numbers;
6977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the digit count is handled programmatically according to the pattern.
6987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
699bee65486a185907111f3be60992433e133ec0e32Scott Russell * <h3>Synchronization</h3>
7007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
7017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Date formats are not synchronized. It is recommended to create separate
7027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * format instances for each thread. If multiple threads access a format
7037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * concurrently, it must be synchronized externally.
7047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *
7057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see          com.ibm.icu.util.Calendar
7067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see          com.ibm.icu.util.GregorianCalendar
7077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see          com.ibm.icu.util.TimeZone
7087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see          DateFormat
7097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see          DateFormatSymbols
7107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see          DecimalFormat
7117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see          TimeZoneFormat
7127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @author       Mark Davis, Chen-Lieh Huang, Alan Liu
7137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 2.0
7147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */
7157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic class SimpleDateFormat extends DateFormat {
7167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // the official serial version ID which says cryptically
7187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // which version we're compatible with
7197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final long serialVersionUID = 4774881970558875024L;
7207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // the internal serial version which says which version was written
7227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // - 0 (default) for version up to JDK 1.1.3
7237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // - 1 for version from JDK 1.1.4, which includes a new field
7247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // - 2 we write additional int for capitalizationSetting
7257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static final int currentSerialVersion = 2;
7267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static boolean DelayedHebrewMonthCheck = false;
7287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
7307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * From calendar field to its level.
7317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Used to order calendar field.
7327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * For example, calendar fields can be defined in the following order:
7337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * year >  month > date > am-pm > hour >  minute
7347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * YEAR --> 10, MONTH -->20, DATE --> 30;
7357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * AM_PM -->40, HOUR --> 50, MINUTE -->60
7367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
7377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final int[] CALENDAR_FIELD_TO_LEVEL =
7387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
7397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*GyM*/ 0, 10, 20,
7407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*wW*/ 20, 30,
7417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*dDEF*/ 30, 20, 30, 30,
7427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*ahHm*/ 40, 50, 50, 60,
743f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        /*sS*/ 70, 80,
7447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*z?Y*/ 0, 0, 10,
7457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*eug*/ 30, 10, 0,
746f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        /*A?*/ 40, 0, 0
7477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    };
7487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
7497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
7507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * From calendar field letter to its level.
7517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Used to order calendar field.
7527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * For example, calendar fields can be defined in the following order:
7537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * year >  month > date > am-pm > hour >  minute
7547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * 'y' --> 10, 'M' -->20, 'd' --> 30; 'a' -->40, 'h' --> 50, 'm' -->60
7557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
7567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final int[] PATTERN_CHAR_TO_LEVEL =
7577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
758f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
759f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    //
760f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
761f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    //       !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /
762f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
763f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    //   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
764bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
765f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    //   @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
7667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        -1, 40, -1, -1, 20, 30, 30,  0, 50, -1, -1, 50, 20, 20, -1,  0,
767f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    //   P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _
7687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        -1, 20, -1, 80, -1, 10,  0, 30,  0, 10,  0, -1, -1, -1, -1, -1,
769f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    //   `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
7707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        -1, 40, -1, 30, 30, 30, -1,  0, 50, -1, -1, 50, -1, 60, -1, -1,
771f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    //   p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~
772f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        -1, 20, 10, 70, -1, 10,  0, 20,  0, 10,  0, -1, -1, -1, -1, -1,
773f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    };
774f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
775f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    /**
776f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * Map calendar field letter into calendar field level.
777f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     */
778f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    private static int getLevelFromChar(char ch) {
779f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        return ch < PATTERN_CHAR_TO_LEVEL.length ? PATTERN_CHAR_TO_LEVEL[ch & 0xff] : -1;
780f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    }
781f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
782f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    private static final boolean[] PATTERN_CHAR_IS_SYNTAX =
783f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    {
784f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        //
785f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        false, false, false, false, false, false, false, false,
786f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        //
787f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        false, false, false, false, false, false, false, false,
788f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        //
789f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        false, false, false, false, false, false, false, false,
790f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        //
791f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        false, false, false, false, false, false, false, false,
792f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        //         !      "      #      $      %      &      '
793f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        false, false, false, false, false, false, false, false,
794f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        //  (      )      *      +      ,      -      .      /
795f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        false, false, false, false, false, false, false, false,
796f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        //  0      1      2      3      4      5      6      7
797f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        false, false, false, false, false, false, false, false,
798f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        //  8      9      :      ;      <      =      >      ?
799bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        false, false, false, false, false, false, false, false,
800f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        //  @      A      B      C      D      E      F      G
801f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        false,  true,  true,  true,  true,  true,  true,  true,
802f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        //  H      I      J      K      L      M      N      O
803f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert         true,  true,  true,  true,  true,  true,  true,  true,
804f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        //  P      Q      R      S      T      U      V      W
805f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert         true,  true,  true,  true,  true,  true,  true,  true,
806f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        //  X      Y      Z      [      \      ]      ^      _
807f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert         true,  true,  true, false, false, false, false, false,
808f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        //  `      a      b      c      d      e      f      g
809f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        false,  true,  true,  true,  true,  true,  true,  true,
810f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        //  h      i      j      k      l      m      n      o
811f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert         true,  true,  true,  true,  true,  true,  true,  true,
812f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        //  p      q      r      s      t      u      v      w
813f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert         true,  true,  true,  true,  true,  true,  true,  true,
814f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        //  x      y      z      {      |      }      ~
815f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert         true,  true,  true, false, false, false, false, false,
8167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    };
8177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
818f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    /**
819f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * Tell if a character can be used to define a field in a format string.
820f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     */
821f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    private static boolean isSyntaxChar(char ch) {
822f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        return ch < PATTERN_CHAR_IS_SYNTAX.length ? PATTERN_CHAR_IS_SYNTAX[ch & 0xff] : false;
823f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    }
824f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
8257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // When calendar uses hebr numbering (i.e. he@calendar=hebrew),
8267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // offset the years within the current millenium down to 1-999
8277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final int HEBREW_CAL_CUR_MILLENIUM_START_YEAR = 5000;
8287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final int HEBREW_CAL_CUR_MILLENIUM_END_YEAR = 6000;
8297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
8317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * The version of the serialized data on the stream.  Possible values:
8327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <ul>
8337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <li><b>0</b> or not present on stream: JDK 1.1.3.  This version
8347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * has no <code>defaultCenturyStart</code> on stream.
8357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <li><b>1</b> JDK 1.1.4 or later.  This version adds
8367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <code>defaultCenturyStart</code>.
8377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <li><b>2</b> This version writes an additional int for
8387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <code>capitalizationSetting</code>.
8397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * </ul>
8407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * When streaming out this class, the most recent format
8417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * and the highest allowable <code>serialVersionOnStream</code>
8427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * is written.
8437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @serial
8447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
8457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int serialVersionOnStream = currentSerialVersion;
8467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
8487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * The pattern string of this formatter.  This is always a non-localized
8497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * pattern.  May not be null.  See class documentation for details.
8507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @serial
8517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
8527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private String pattern;
8537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
8557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * The override string of this formatter.  Used to override the
8567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * numbering system for one or more fields.
8577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @serial
8587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
8597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private String override;
8607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
8627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * The hash map used for number format overrides.
8637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @serial
8647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
8657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private HashMap<String, NumberFormat> numberFormatters;
8667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
8687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * The hash map used for number format overrides.
8697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @serial
8707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
8717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private HashMap<Character, String> overrideMap;
8727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
8747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * The symbols used by this formatter for week names, month names,
8757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * etc.  May not be null.
8767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @serial
8777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see DateFormatSymbols
8787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
8797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private DateFormatSymbols formatData;
8807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private transient ULocale locale;
8827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
8847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * We map dates with two-digit years into the century starting at
8857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <code>defaultCenturyStart</code>, which may be any date.  May
8867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * not be null.
8877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @serial
8887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @since JDK1.1.4
8897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
8907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private Date defaultCenturyStart;
8917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private transient int defaultCenturyStartYear;
8937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // defaultCenturyBase is set when an instance is created
8957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // and may be used for calculating defaultCenturyStart when needed.
8967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private transient long defaultCenturyBase;
8977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
8987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final int millisPerHour = 60 * 60 * 1000;
8997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // When possessing ISO format, the ERA may be ommitted is the
9017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // year specifier is a negative number.
9027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final int ISOSpecialEra = -32000;
9037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // This prefix is designed to NEVER MATCH real text, in order to
9057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // suppress the parsing of negative numbers.  Adjust as needed (if
9067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // this becomes valid Unicode).
9077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final String SUPPRESS_NEGATIVE_PREFIX = "\uAB00";
9087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
9107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * If true, this object supports fast formatting using the
9117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * subFormat variant that takes a StringBuffer.
9127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
9137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private transient boolean useFastFormat;
9147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
9167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *  The time zone sub-formatter, introduced in ICU 4.8
9177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
9187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private volatile TimeZoneFormat tzFormat;
9197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
9217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * BreakIterator to use for capitalization
9227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
9237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private transient BreakIterator capitalizationBrkIter = null;
9247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
9267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *  Capitalization setting, introduced in ICU 50
9277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *  Special serialization, see writeObject & readObject below
9287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
9297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *  Hoisted to DateFormat in ICU 53, get value with
9307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *  getContext(DisplayContext.Type.CAPITALIZATION)
9317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
9327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // private transient DisplayContext capitalizationSetting;
9337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
9357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *  Old defaultCapitalizationContext field
9367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *  from ICU 49.1:
9377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
9387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    //private ContextValue defaultCapitalizationContext;
9397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
9407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *  Old ContextValue enum, preserved only to avoid
9417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *  deserialization errs from ICU 49.1.
9427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
9437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @SuppressWarnings("unused")
9447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private enum ContextValue {
9457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        UNKNOWN,
9467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,
9477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE,
9487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CAPITALIZATION_FOR_UI_LIST_OR_MENU,
9497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CAPITALIZATION_FOR_STANDALONE
9507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
9517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
9537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a SimpleDateFormat using the default pattern for the default <code>FORMAT</code>
9547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * locale.  <b>Note:</b> Not all locales support SimpleDateFormat; for full
9557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * generality, use the factory methods in the DateFormat class.
9567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
9577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see DateFormat
9587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see Category#FORMAT
9597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
9607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
9617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public SimpleDateFormat() {
9627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this(getDefaultPattern(), null, null, null, null, true, null);
9637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
9647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
9667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a SimpleDateFormat using the given pattern in the default <code>FORMAT</code>
9677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * locale.  <b>Note:</b> Not all locales support SimpleDateFormat; for full
9687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * generality, use the factory methods in the DateFormat class.
9697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see Category#FORMAT
9707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
9717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
9727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public SimpleDateFormat(String pattern)
9737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
9747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this(pattern, null, null, null, null, true, null);
9757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
9767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
9787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a SimpleDateFormat using the given pattern and locale.
9797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <b>Note:</b> Not all locales support SimpleDateFormat; for full
9807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * generality, use the factory methods in the DateFormat class.
9817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
9827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
9837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public SimpleDateFormat(String pattern, Locale loc)
9847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
9857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this(pattern, null, null, null, ULocale.forLocale(loc), true, null);
9867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
9877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
9897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a SimpleDateFormat using the given pattern and locale.
9907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <b>Note:</b> Not all locales support SimpleDateFormat; for full
9917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * generality, use the factory methods in the DateFormat class.
9927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.2
9937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
9947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public SimpleDateFormat(String pattern, ULocale loc)
9957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
9967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this(pattern, null, null, null, loc, true, null);
9977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
9987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
9997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
10007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a SimpleDateFormat using the given pattern , override and locale.
10017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param pattern The pattern to be used
10027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param override The override string.  A numbering system override string can take one of the following forms:
10037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *     1). If just a numbering system name is specified, it applies to all numeric fields in the date format pattern.
10047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *     2). To specify an alternate numbering system on a field by field basis, use the field letters from the pattern
10057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *         followed by an = sign, followed by the numbering system name.  For example, to specify that just the year
10067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *         be formatted using Hebrew digits, use the override "y=hebr".  Multiple overrides can be specified in a single
10077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *         string by separating them with a semi-colon. For example, the override string "m=thai;y=deva" would format using
10087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *         Thai digits for the month and Devanagari digits for the year.
10097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param loc The locale to be used
10107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 4.2
10117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
10127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public SimpleDateFormat(String pattern, String override, ULocale loc)
10137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
10147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this(pattern, null, null, null, loc, false,override);
10157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
10167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
10177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
10187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Constructs a SimpleDateFormat using the given pattern and
10197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * locale-specific symbol data.
10207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Warning: uses default <code>FORMAT</code> locale for digits!
10217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
10227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
10237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public SimpleDateFormat(String pattern, DateFormatSymbols formatData)
10247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
10257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this(pattern, (DateFormatSymbols)formatData.clone(), null, null, null, true, null);
10267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
10277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
10287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
10297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @internal
10307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @deprecated This API is ICU internal only.
10317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
10327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Deprecated
10337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public SimpleDateFormat(String pattern, DateFormatSymbols formatData, ULocale loc)
10347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
10357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this(pattern, (DateFormatSymbols)formatData.clone(), null, null, loc, true,null);
10367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
10377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
10387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
10397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Package-private constructor that allows a subclass to specify
10407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * whether it supports fast formatting.
10417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
10427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * TODO make this API public.
10437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
10447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    SimpleDateFormat(String pattern, DateFormatSymbols formatData, Calendar calendar, ULocale locale,
10457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                     boolean useFastFormat, String override) {
10467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this(pattern, (DateFormatSymbols)formatData.clone(), (Calendar)calendar.clone(), null, locale, useFastFormat,override);
10477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
10487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
10497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
10507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * The constructor called from all other SimpleDateFormat constructors
10517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
10527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private SimpleDateFormat(String pattern, DateFormatSymbols formatData, Calendar calendar,
10537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            NumberFormat numberFormat, ULocale locale, boolean useFastFormat,String override) {
10547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this.pattern = pattern;
10557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this.formatData = formatData;
10567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this.calendar = calendar;
10577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this.numberFormat = numberFormat;
10587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this.locale = locale; // time zone formatting
10597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this.useFastFormat = useFastFormat;
10607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this.override = override;
10617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        initialize();
10627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
10637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
10647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
10657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Creates an instance of SimpleDateFormat for the given format configuration
10667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param formatConfig the format configuration
10677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return A SimpleDateFormat instance
10687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @internal
10697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @deprecated This API is ICU internal only.
10707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
10717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Deprecated
10727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static SimpleDateFormat getInstance(Calendar.FormatConfiguration formatConfig) {
10737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
10747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String ostr = formatConfig.getOverrideString();
10757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        boolean useFast = ( ostr != null && ostr.length() > 0 );
10767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
10777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return new SimpleDateFormat(formatConfig.getPatternString(),
10787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    formatConfig.getDateFormatSymbols(),
10797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    formatConfig.getCalendar(),
10807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    null,
10817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    formatConfig.getLocale(),
10827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    useFast,
10837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    formatConfig.getOverrideString());
10847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
10857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
10867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
10877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Initialized fields
10887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
10897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private void initialize() {
10907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (locale == null) {
10917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            locale = ULocale.getDefault(Category.FORMAT);
10927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
10937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (formatData == null) {
10947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            formatData = new DateFormatSymbols(locale);
10957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
10967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (calendar == null) {
10977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            calendar = Calendar.getInstance(locale);
10987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
10997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (numberFormat == null) {
11007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            NumberingSystem ns = NumberingSystem.getInstance(locale);
11017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (ns.isAlgorithmic()) {
11027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                numberFormat = NumberFormat.getInstance(locale);
11037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
11047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                String digitString = ns.getDescription();
11057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                String nsName = ns.getName();
11067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // Use a NumberFormat optimized for date formatting
11077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                numberFormat = new DateNumberFormat(locale, digitString, nsName);
11087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
11097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
11107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Note: deferring calendar calculation until when we really need it.
11117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Instead, we just record time of construction for backward compatibility.
11127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        defaultCenturyBase = System.currentTimeMillis();
11137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
11147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        setLocale(calendar.getLocale(ULocale.VALID_LOCALE ), calendar.getLocale(ULocale.ACTUAL_LOCALE));
11157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        initLocalZeroPaddingNumberFormat();
11167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
11177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (override != null) {
11187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert           initNumberFormatters(locale);
11197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
11207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
11217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
11227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
11237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Private method lazily instantiate the TimeZoneFormat field
11247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param bForceUpdate when true, check if tzFormat is synchronized with
11257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * the current numberFormat and update its digits if necessary. When false,
11267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * this check is skipped.
11277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
11287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private synchronized void initializeTimeZoneFormat(boolean bForceUpdate) {
11297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (bForceUpdate || tzFormat == null) {
11307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            tzFormat = TimeZoneFormat.getInstance(locale);
11317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
11327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            String digits = null;
11337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (numberFormat instanceof DecimalFormat) {
11347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                DecimalFormatSymbols decsym = ((DecimalFormat) numberFormat).getDecimalFormatSymbols();
11357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                digits = new String(decsym.getDigits());
11367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (numberFormat instanceof DateNumberFormat) {
11377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                digits = new String(((DateNumberFormat)numberFormat).getDigits());
11387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
11397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
11407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (digits != null) {
11417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (!tzFormat.getGMTOffsetDigits().equals(digits)) {
11427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (tzFormat.isFrozen()) {
11437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        tzFormat = tzFormat.cloneAsThawed();
11447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
11457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    tzFormat.setGMTOffsetDigits(digits);
11467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
11477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
11487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
11497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
11507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
11517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
11527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Private method, returns non-null TimeZoneFormat.
11537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return the TimeZoneFormat used by this formatter.
11547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
11557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private TimeZoneFormat tzFormat() {
11567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (tzFormat == null) {
11577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            initializeTimeZoneFormat(false);
11587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
11597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return tzFormat;
11607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
11617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
11627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // privates for the default pattern
11637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static ULocale cachedDefaultLocale = null;
11647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static String cachedDefaultPattern = null;
11657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final String FALLBACKPATTERN = "yy/MM/dd HH:mm";
11667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
11677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
11687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the default date and time pattern (SHORT) for the default locale.
11697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * This method is only used by the default SimpleDateFormat constructor.
11707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
11717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static synchronized String getDefaultPattern() {
11727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        ULocale defaultLocale = ULocale.getDefault(Category.FORMAT);
11737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (!defaultLocale.equals(cachedDefaultLocale)) {
11747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            cachedDefaultLocale = defaultLocale;
11757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            Calendar cal = Calendar.getInstance(cachedDefaultLocale);
11767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            try {
11777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                CalendarData calData = new CalendarData(cachedDefaultLocale, cal.getType());
11787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                String[] dateTimePatterns = calData.getDateTimePatterns();
11797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                int glueIndex = 8;
11807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (dateTimePatterns.length >= 13)
11817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                {
11827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    glueIndex += (SHORT + 1);
11837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
11847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                cachedDefaultPattern = MessageFormat.format(dateTimePatterns[glueIndex],
11857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        new Object[] {dateTimePatterns[SHORT], dateTimePatterns[SHORT + 4]});
11867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } catch (MissingResourceException e) {
11877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                cachedDefaultPattern = FALLBACKPATTERN;
11887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
11897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
11907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return cachedDefaultPattern;
11917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
11927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
11937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /* Define one-century window into which to disambiguate dates using
11947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * two-digit years.
11957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
11967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private void parseAmbiguousDatesAsAfter(Date startDate) {
11977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        defaultCenturyStart = startDate;
11987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        calendar.setTime(startDate);
11997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        defaultCenturyStartYear = calendar.get(Calendar.YEAR);
12007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
12017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
12027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /* Initialize defaultCenturyStart and defaultCenturyStartYear by base time.
12037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * The default start time is 80 years before the creation time of this object.
12047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
12057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private void initializeDefaultCenturyStart(long baseTime) {
12067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        defaultCenturyBase = baseTime;
12077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // clone to avoid messing up date stored in calendar object
12087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // when this method is called while parsing
12097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Calendar tmpCal = (Calendar)calendar.clone();
12107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        tmpCal.setTimeInMillis(baseTime);
12117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        tmpCal.add(Calendar.YEAR, -80);
12127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        defaultCenturyStart = tmpCal.getTime();
12137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        defaultCenturyStartYear = tmpCal.get(Calendar.YEAR);
12147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
12157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
12167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /* Gets the default century start date for this object */
12177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private Date getDefaultCenturyStart() {
12187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (defaultCenturyStart == null) {
12197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // not yet initialized
12207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            initializeDefaultCenturyStart(defaultCenturyBase);
12217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
12227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return defaultCenturyStart;
12237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
12247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
12257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /* Gets the default century start year for this object */
12267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int getDefaultCenturyStartYear() {
12277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (defaultCenturyStart == null) {
12287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // not yet initialized
12297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            initializeDefaultCenturyStart(defaultCenturyBase);
12307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
12317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return defaultCenturyStartYear;
12327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
12337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
12347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
12357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Sets the 100-year period 2-digit years will be interpreted as being in
12367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * to begin on the date the user specifies.
12377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param startDate During parsing, two digit years will be placed in the range
12387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <code>startDate</code> to <code>startDate + 100 years</code>.
12397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
12407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
12417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void set2DigitYearStart(Date startDate) {
12427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        parseAmbiguousDatesAsAfter(startDate);
12437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
12447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
12457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
12467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns the beginning date of the 100-year period 2-digit years are interpreted
12477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * as being within.
12487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return the start of the 100-year period into which two digit years are
12497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * parsed
12507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
12517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
12527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public Date get2DigitYearStart() {
12537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return getDefaultCenturyStart();
12547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
12557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
12567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
12577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * {@icu} Set a particular DisplayContext value in the formatter,
12587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * such as CAPITALIZATION_FOR_STANDALONE. Note: For getContext, see
12597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * DateFormat.
12607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
12617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param context The DisplayContext value to set.
1262f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * @stable ICU 53
12637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
12647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // Here we override the DateFormat implementation in order to lazily initialize relevant items
12657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setContext(DisplayContext context) {
12667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        super.setContext(context);
12677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (capitalizationBrkIter == null && (context==DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
12687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert              context==DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU ||
12697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert              context==DisplayContext.CAPITALIZATION_FOR_STANDALONE)) {
12707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            capitalizationBrkIter = BreakIterator.getSentenceInstance(locale);
12717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
12727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
12737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
12747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
12757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Formats a date or time, which is the standard millis
12767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * since January 1, 1970, 00:00:00 GMT.
12777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <p>Example: using the US locale:
1278bee65486a185907111f3be60992433e133ec0e32Scott Russell     * "yyyy.MM.dd G 'at' HH:mm:ss zzz" -&gt;&gt; 1996.07.10 AD at 15:08:56 PDT
12797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param cal the calendar whose date-time value is to be formatted into a date-time string
12807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param toAppendTo where the new date-time text is to be appended
12817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param pos the formatting position. On input: an alignment field,
12827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * if desired. On output: the offsets of the alignment field.
12837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return the formatted date-time string.
12847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see DateFormat
12857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
12867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
12877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public StringBuffer format(Calendar cal, StringBuffer toAppendTo,
12887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                               FieldPosition pos) {
12897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        TimeZone backupTZ = null;
12907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (cal != calendar && !cal.getType().equals(calendar.getType())) {
12917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Different calendar type
12927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // We use the time and time zone from the input calendar, but
12937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // do not use the input calendar for field calculation.
12947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            calendar.setTimeInMillis(cal.getTimeInMillis());
12957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            backupTZ = calendar.getTimeZone();
12967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            calendar.setTimeZone(cal.getTimeZone());
12977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            cal = calendar;
12987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
12997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        StringBuffer result = format(cal, getContext(DisplayContext.Type.CAPITALIZATION), toAppendTo, pos, null);
13007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (backupTZ != null) {
13017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Restore the original time zone
13027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            calendar.setTimeZone(backupTZ);
13037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
13047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return result;
13057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
13067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
13077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // The actual method to format date. If List attributes is not null,
13087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // then attribute information will be recorded.
13097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private StringBuffer format(Calendar cal, DisplayContext capitalizationContext,
13107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            StringBuffer toAppendTo, FieldPosition pos, List<FieldPosition> attributes) {
13117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Initialize
13127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        pos.setBeginIndex(0);
13137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        pos.setEndIndex(0);
13147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
13157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Careful: For best performance, minimize the number of calls
13167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // to StringBuffer.append() by consolidating appends when
13177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // possible.
13187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
13197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Object[] items = getPatternItems();
13207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (int i = 0; i < items.length; i++) {
13217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (items[i] instanceof String) {
13227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                toAppendTo.append((String)items[i]);
13237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
13247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                PatternItem item = (PatternItem)items[i];
13257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                int start = 0;
13267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (attributes != null) {
13277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Save the current length
13287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    start = toAppendTo.length();
13297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
13307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (useFastFormat) {
13317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    subFormat(toAppendTo, item.type, item.length, toAppendTo.length(),
13327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                              i, capitalizationContext, pos, cal);
13337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
13347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    toAppendTo.append(subFormat(item.type, item.length, toAppendTo.length(),
13357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                                i, capitalizationContext, pos, cal));
13367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
13377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (attributes != null) {
13387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Check the sub format length
13397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    int end = toAppendTo.length();
13407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (end - start > 0) {
13417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // Append the attribute to the list
13427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        DateFormat.Field attr = patternCharToDateFormatField(item.type);
13437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        FieldPosition fp = new FieldPosition(attr);
13447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        fp.setBeginIndex(start);
13457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        fp.setEndIndex(end);
13467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        attributes.add(fp);
13477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
13487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
13497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
13507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
13517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return toAppendTo;
13527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
13537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
13547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
13557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // Map pattern character to index
13567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final int[] PATTERN_CHAR_TO_INDEX =
13577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
1358f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1359f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    //
1360f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1361f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    //       !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /
1362f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1363f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    //   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
1364bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1365f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    //   @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
13667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        -1, 22, -1, -1, 10,  9, 11,  0,  5, -1, -1, 16, 26,  2, -1, 31,
1367f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    //   P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _
13687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        -1, 27, -1,  8, -1, 30, 29, 13, 32, 18, 23, -1, -1, -1, -1, -1,
1369f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    //   `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
13707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        -1, 14, -1, 25,  3, 19, -1, 21, 15, -1, -1,  4, -1,  6, -1, -1,
1371f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    //   p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~
1372f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        -1, 28, 34,  7, -1, 20, 24, 12, 33,  1, 17, -1, -1, -1, -1, -1,
13737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    };
13747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1375f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    private static int getIndexFromChar(char ch) {
1376f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        return ch < PATTERN_CHAR_TO_INDEX.length ? PATTERN_CHAR_TO_INDEX[ch & 0xff] : -1;
1377f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    }
1378f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
13797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // Map pattern character index to Calendar field number
13807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final int[] PATTERN_INDEX_TO_CALENDAR_FIELD =
13817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
13827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*GyM*/ Calendar.ERA, Calendar.YEAR, Calendar.MONTH,
13837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*dkH*/ Calendar.DATE, Calendar.HOUR_OF_DAY, Calendar.HOUR_OF_DAY,
13847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*msS*/ Calendar.MINUTE, Calendar.SECOND, Calendar.MILLISECOND,
13857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*EDF*/ Calendar.DAY_OF_WEEK, Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK_IN_MONTH,
13867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*wWa*/ Calendar.WEEK_OF_YEAR, Calendar.WEEK_OF_MONTH, Calendar.AM_PM,
13877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*hKz*/ Calendar.HOUR, Calendar.HOUR, Calendar.ZONE_OFFSET,
13887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*Yeu*/ Calendar.YEAR_WOY, Calendar.DOW_LOCAL, Calendar.EXTENDED_YEAR,
1389f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        /*gAZ*/ Calendar.JULIAN_DAY, Calendar.MILLISECONDS_IN_DAY, Calendar.ZONE_OFFSET /* also DST_OFFSET */,
1390f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        /*v*/   Calendar.ZONE_OFFSET /* also DST_OFFSET */,
13917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*c*/   Calendar.DOW_LOCAL,
13927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*L*/   Calendar.MONTH,
13937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*Qq*/  Calendar.MONTH, Calendar.MONTH,
1394f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        /*V*/   Calendar.ZONE_OFFSET /* also DST_OFFSET */,
13957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*U*/   Calendar.YEAR,
1396f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        /*O*/   Calendar.ZONE_OFFSET /* also DST_OFFSET */,
1397f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        /*Xx*/  Calendar.ZONE_OFFSET /* also DST_OFFSET */, Calendar.ZONE_OFFSET /* also DST_OFFSET */,
1398f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        /*r*/   Calendar.EXTENDED_YEAR /* not an exact match */,
1399f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        /*:*/   -1, /* => no useful mapping to any calendar field, can't use protected Calendar.BASE_FIELD_COUNT */
14007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    };
14017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
14027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // Map pattern character index to DateFormat field number
14037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final int[] PATTERN_INDEX_TO_DATE_FORMAT_FIELD = {
14047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*GyM*/ DateFormat.ERA_FIELD, DateFormat.YEAR_FIELD, DateFormat.MONTH_FIELD,
14057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*dkH*/ DateFormat.DATE_FIELD, DateFormat.HOUR_OF_DAY1_FIELD, DateFormat.HOUR_OF_DAY0_FIELD,
14067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*msS*/ DateFormat.MINUTE_FIELD, DateFormat.SECOND_FIELD, DateFormat.FRACTIONAL_SECOND_FIELD,
14077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*EDF*/ DateFormat.DAY_OF_WEEK_FIELD, DateFormat.DAY_OF_YEAR_FIELD, DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD,
14087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*wWa*/ DateFormat.WEEK_OF_YEAR_FIELD, DateFormat.WEEK_OF_MONTH_FIELD, DateFormat.AM_PM_FIELD,
14097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*hKz*/ DateFormat.HOUR1_FIELD, DateFormat.HOUR0_FIELD, DateFormat.TIMEZONE_FIELD,
14107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*Yeu*/ DateFormat.YEAR_WOY_FIELD, DateFormat.DOW_LOCAL_FIELD, DateFormat.EXTENDED_YEAR_FIELD,
14117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*gAZ*/ DateFormat.JULIAN_DAY_FIELD, DateFormat.MILLISECONDS_IN_DAY_FIELD, DateFormat.TIMEZONE_RFC_FIELD,
14127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*v*/   DateFormat.TIMEZONE_GENERIC_FIELD,
14137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*c*/   DateFormat.STANDALONE_DAY_FIELD,
14147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*L*/   DateFormat.STANDALONE_MONTH_FIELD,
14157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*Qq*/  DateFormat.QUARTER_FIELD, DateFormat.STANDALONE_QUARTER_FIELD,
14167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*V*/   DateFormat.TIMEZONE_SPECIAL_FIELD,
14177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*U*/   DateFormat.YEAR_NAME_FIELD,
14187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*O*/   DateFormat.TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD,
14197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*Xx*/  DateFormat.TIMEZONE_ISO_FIELD, DateFormat.TIMEZONE_ISO_LOCAL_FIELD,
1420f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        /*r*/   DateFormat.RELATED_YEAR,
1421bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        /*(no pattern character defined for this)*/   DateFormat.TIME_SEPARATOR,
14227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    };
14237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
14247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // Map pattern character index to DateFormat.Field
14257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final DateFormat.Field[] PATTERN_INDEX_TO_DATE_FORMAT_ATTRIBUTE = {
14267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*GyM*/ DateFormat.Field.ERA, DateFormat.Field.YEAR, DateFormat.Field.MONTH,
14277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*dkH*/ DateFormat.Field.DAY_OF_MONTH, DateFormat.Field.HOUR_OF_DAY1, DateFormat.Field.HOUR_OF_DAY0,
14287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*msS*/ DateFormat.Field.MINUTE, DateFormat.Field.SECOND, DateFormat.Field.MILLISECOND,
14297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*EDF*/ DateFormat.Field.DAY_OF_WEEK, DateFormat.Field.DAY_OF_YEAR, DateFormat.Field.DAY_OF_WEEK_IN_MONTH,
14307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*wWa*/ DateFormat.Field.WEEK_OF_YEAR, DateFormat.Field.WEEK_OF_MONTH, DateFormat.Field.AM_PM,
14317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*hKz*/ DateFormat.Field.HOUR1, DateFormat.Field.HOUR0, DateFormat.Field.TIME_ZONE,
14327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*Yeu*/ DateFormat.Field.YEAR_WOY, DateFormat.Field.DOW_LOCAL, DateFormat.Field.EXTENDED_YEAR,
14337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*gAZ*/ DateFormat.Field.JULIAN_DAY, DateFormat.Field.MILLISECONDS_IN_DAY, DateFormat.Field.TIME_ZONE,
14347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*v*/   DateFormat.Field.TIME_ZONE,
14357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*c*/   DateFormat.Field.DAY_OF_WEEK,
14367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*L*/   DateFormat.Field.MONTH,
14377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*Qq*/  DateFormat.Field.QUARTER, DateFormat.Field.QUARTER,
14387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*V*/   DateFormat.Field.TIME_ZONE,
14397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*U*/   DateFormat.Field.YEAR,
14407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*O*/   DateFormat.Field.TIME_ZONE,
14417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*Xx*/  DateFormat.Field.TIME_ZONE, DateFormat.Field.TIME_ZONE,
1442f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        /*r*/   DateFormat.Field.RELATED_YEAR,
1443bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        /*(no pattern character defined for this)*/   DateFormat.Field.TIME_SEPARATOR,
14447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    };
14457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
14467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
14477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns a DateFormat.Field constant associated with the specified format pattern
14487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * character.
14497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
14507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param ch The pattern character
14517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return DateFormat.Field associated with the pattern character
14527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
14537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.8
14547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
14557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected DateFormat.Field patternCharToDateFormatField(char ch) {
1456f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        int patternCharIndex = getIndexFromChar(ch);
14577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (patternCharIndex != -1) {
14587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return PATTERN_INDEX_TO_DATE_FORMAT_ATTRIBUTE[patternCharIndex];
14597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
14607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return null;
14617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
14627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
14637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
14647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Formats a single field, given its pattern character.  Subclasses may
14657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * override this method in order to modify or add formatting
14667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * capabilities.
14677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param ch the pattern character
14687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param count the number of times ch is repeated in the pattern
14697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param beginOffset the offset of the output string at the start of
14707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * this field; used to set pos when appropriate
14717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param pos receives the position of a field, when appropriate
14727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param fmtData the symbols for this formatter
14737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
14747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
14757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected String subFormat(char ch, int count, int beginOffset,
14767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                               FieldPosition pos, DateFormatSymbols fmtData,
14777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                               Calendar cal)
14787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        throws IllegalArgumentException
14797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
14807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Note: formatData is ignored
14817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return subFormat(ch, count, beginOffset, 0, DisplayContext.CAPITALIZATION_NONE, pos, cal);
14827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
14837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
14847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     /**
14857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Formats a single field. This is the version called internally; it
14867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * adds fieldNum and capitalizationContext parameters.
14877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
14887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @internal
14897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @deprecated This API is ICU internal only.
14907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
14917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Deprecated
14927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected String subFormat(char ch, int count, int beginOffset,
14937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                               int fieldNum, DisplayContext capitalizationContext,
14947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                               FieldPosition pos,
14957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                               Calendar cal)
14967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
14977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        StringBuffer buf = new StringBuffer();
14987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        subFormat(buf, ch, count, beginOffset, fieldNum, capitalizationContext, pos, cal);
14997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return buf.toString();
15007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
15017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
15027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert   /**
15037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Formats a single field; useFastFormat variant.  Reuses a
15047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * StringBuffer for results instead of creating a String on the
15057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * heap for each call.
15067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
15077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * NOTE We don't really need the beginOffset parameter, EXCEPT for
15087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * the need to support the slow subFormat variant (above) which
15097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * has to pass it in to us.
15107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
15117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @internal
15127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @deprecated This API is ICU internal only.
15137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
15147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Deprecated
15157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @SuppressWarnings("fallthrough")
15167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected void subFormat(StringBuffer buf,
15177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                             char ch, int count, int beginOffset,
15187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                             int fieldNum, DisplayContext capitalizationContext,
15197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                             FieldPosition pos,
15207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                             Calendar cal) {
15217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
15227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        final int maxIntCount = Integer.MAX_VALUE;
15237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        final int bufstart = buf.length();
15247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        TimeZone tz = cal.getTimeZone();
15257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        long date = cal.getTimeInMillis();
15267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String result = null;
15277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1528f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        int patternCharIndex = getIndexFromChar(ch);
15297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (patternCharIndex == -1) {
15307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (ch == 'l') { // (SMALL LETTER L) deprecated placeholder for leap month marker, ignore
15317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return;
15327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
15337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException("Illegal pattern character " +
15347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                                   "'" + ch + "' in \"" +
15357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                                   pattern + '"');
15367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
15377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
15387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
15397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        final int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
1540f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        int value = 0;
1541f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        // Don't get value unless it is useful
1542f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        if (field >= 0) {
1543f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            value = (patternCharIndex != DateFormat.RELATED_YEAR)? cal.get(field): cal.getRelatedYear();
1544f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        }
15457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
15467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        NumberFormat currentNumberFormat = getNumberFormat(ch);
15477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        DateFormatSymbols.CapitalizationContextUsage capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.OTHER;
15487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
15497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        switch (patternCharIndex) {
15507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 0: // 'G' - ERA
15517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if ( cal.getType().equals("chinese") || cal.getType().equals("dangi") ) {
15527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // moved from ChineseDateFormat
15537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                zeroPaddingNumber(currentNumberFormat, buf, value, 1, 9);
15547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
15557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (count == 5) {
15567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    safeAppend(formatData.narrowEras, value, buf);
15577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.ERA_NARROW;
15587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else if (count == 4) {
15597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    safeAppend(formatData.eraNames, value, buf);
15607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.ERA_WIDE;
15617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
15627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    safeAppend(formatData.eras, value, buf);
15637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.ERA_ABBREV;
15647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
15657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
15667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
15677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 30: // 'U' - YEAR_NAME_FIELD
15687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (formatData.shortYearNames != null && value <= formatData.shortYearNames.length) {
15697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                safeAppend(formatData.shortYearNames, value-1, buf);
15707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                break;
15717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
15727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // else fall through to numeric year handling, do not break here
15737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 1: // 'y' - YEAR
15747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 18: // 'Y' - YEAR_WOY
15757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if ( override != null && (override.compareTo("hebr") == 0 || override.indexOf("y=hebr") >= 0) &&
15767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    value > HEBREW_CAL_CUR_MILLENIUM_START_YEAR && value < HEBREW_CAL_CUR_MILLENIUM_END_YEAR ) {
15777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                value -= HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
15787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
15797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            /* According to the specification, if the number of pattern letters ('y') is 2,
15807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             * the year is truncated to 2 digits; otherwise it is interpreted as a number.
15817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             * But the original code process 'y', 'yy', 'yyy' in the same way. and process
15827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             * patterns with 4 or more than 4 'y' characters in the same way.
15837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             * So I change the codes to meet the specification. [Richard/GCl]
15847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert             */
15857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (count == 2) {
15867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                zeroPaddingNumber(currentNumberFormat,buf, value, 2, 2); // clip 1996 to 96
15877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else { //count = 1 or count > 2
15887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                zeroPaddingNumber(currentNumberFormat,buf, value, count, maxIntCount);
15897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
15907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
15917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 2: // 'M' - MONTH
15927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 26: // 'L' - STANDALONE MONTH
15937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if ( cal.getType().equals("hebrew")) {
15947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                boolean isLeap = HebrewCalendar.isLeapYear(cal.get(Calendar.YEAR));
15957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (isLeap && value == 6 && count >= 3 ) {
15967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    value = 13; // Show alternate form for Adar II in leap years in Hebrew calendar.
15977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
15987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (!isLeap && value >= 6 && count < 3 ) {
15997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    value--; // Adjust the month number down 1 in Hebrew non-leap years, i.e. Adar is 6, not 7.
16007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
16017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
16027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            int isLeapMonth = (formatData.leapMonthPatterns != null && formatData.leapMonthPatterns.length >= DateFormatSymbols.DT_MONTH_PATTERN_COUNT)?
16037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                     cal.get(Calendar.IS_LEAP_MONTH): 0;
16047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // should consolidate the next section by using arrays of pointers & counts for the right symbols...
16057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (count == 5) {
16067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (patternCharIndex == 2) {
16077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    safeAppendWithMonthPattern(formatData.narrowMonths, value, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_FORMAT_NARROW]: null);
16087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
16097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    safeAppendWithMonthPattern(formatData.standaloneNarrowMonths, value, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_STANDALONE_NARROW]: null);
16107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
16117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.MONTH_NARROW;
16127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 4) {
16137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (patternCharIndex == 2) {
16147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    safeAppendWithMonthPattern(formatData.months, value, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_FORMAT_WIDE]: null);
16157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.MONTH_FORMAT;
16167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
16177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    safeAppendWithMonthPattern(formatData.standaloneMonths, value, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_STANDALONE_WIDE]: null);
16187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.MONTH_STANDALONE;
16197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
16207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 3) {
16217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (patternCharIndex == 2) {
16227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    safeAppendWithMonthPattern(formatData.shortMonths, value, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_FORMAT_ABBREV]: null);
16237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.MONTH_FORMAT;
16247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
16257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    safeAppendWithMonthPattern(formatData.standaloneShortMonths, value, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_STANDALONE_ABBREV]: null);
16267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.MONTH_STANDALONE;
16277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
16287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
16297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                StringBuffer monthNumber = new StringBuffer();
16307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                zeroPaddingNumber(currentNumberFormat, monthNumber, value+1, count, maxIntCount);
16317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                String[] monthNumberStrings = new String[1];
16327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                monthNumberStrings[0] = monthNumber.toString();
16337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                safeAppendWithMonthPattern(monthNumberStrings, 0, buf, (isLeapMonth!=0)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_NUMERIC]: null);
16347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
16357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
16367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 4: // 'k' - HOUR_OF_DAY (1..24)
16377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (value == 0) {
16387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                zeroPaddingNumber(currentNumberFormat,buf,
16397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                  cal.getMaximum(Calendar.HOUR_OF_DAY)+1,
16407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                  count, maxIntCount);
16417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
16427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                zeroPaddingNumber(currentNumberFormat,buf, value, count, maxIntCount);
16437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
16447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
16457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 8: // 'S' - FRACTIONAL_SECOND
16467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Fractional seconds left-justify
16477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            {
16487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                numberFormat.setMinimumIntegerDigits(Math.min(3, count));
16497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                numberFormat.setMaximumIntegerDigits(maxIntCount);
16507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (count == 1) {
16517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    value /= 100;
16527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else if (count == 2) {
16537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    value /= 10;
16547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
16557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                FieldPosition p = new FieldPosition(-1);
16567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                numberFormat.format((long) value, buf, p);
16577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (count > 3) {
16587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    numberFormat.setMinimumIntegerDigits(count - 3);
16597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    numberFormat.format(0L, buf, p);
16607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
16617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
16627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
16637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 19: // 'e' - DOW_LOCAL (use DOW_LOCAL for numeric, DAY_OF_WEEK for format names)
16647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (count < 3) {
16657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                zeroPaddingNumber(currentNumberFormat,buf, value, count, maxIntCount);
16667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                break;
16677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
16687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // For alpha day-of-week, we don't want DOW_LOCAL,
16697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // we need the standard DAY_OF_WEEK.
16707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            value = cal.get(Calendar.DAY_OF_WEEK);
16717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // fall through, do not break here
16727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 9: // 'E' - DAY_OF_WEEK
16737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (count == 5) {
16747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                safeAppend(formatData.narrowWeekdays, value, buf);
16757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_NARROW;
16767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 4) {
16777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                safeAppend(formatData.weekdays, value, buf);
16787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_FORMAT;
16797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 6 && formatData.shorterWeekdays != null) {
16807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                safeAppend(formatData.shorterWeekdays, value, buf);
16817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_FORMAT;
16827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {// count <= 3, use abbreviated form if exists
16837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                safeAppend(formatData.shortWeekdays, value, buf);
16847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_FORMAT;
16857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
16867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
16877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 14: // 'a' - AM_PM
1688f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            // formatData.ampmsNarrow may be null when deserializing DateFormatSymbolsfrom old version
1689f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            if (count < 5 || formatData.ampmsNarrow == null) {
1690f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                safeAppend(formatData.ampms, value, buf);
1691f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            } else {
1692f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                safeAppend(formatData.ampmsNarrow, value, buf);
1693f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            }
16947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
16957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 15: // 'h' - HOUR (1..12)
16967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (value == 0) {
16977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                zeroPaddingNumber(currentNumberFormat,buf,
16987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                  cal.getLeastMaximum(Calendar.HOUR)+1,
16997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                  count, maxIntCount);
17007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
17017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                zeroPaddingNumber(currentNumberFormat,buf, value, count, maxIntCount);
17027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
17037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
17047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
17057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 17: // 'z' - TIMEZONE_FIELD
17067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (count < 4) {
17077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "z", "zz", "zzz"
17087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.SPECIFIC_SHORT, tz, date);
17097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.METAZONE_SHORT;
17107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
17117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.SPECIFIC_LONG, tz, date);
17127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.METAZONE_LONG;
17137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
17147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            buf.append(result);
17157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
17167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 23: // 'Z' - TIMEZONE_RFC_FIELD
17177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (count < 4) {
17187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // RFC822 format - equivalent to ISO 8601 local offset fixed width format
17197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.ISO_BASIC_LOCAL_FULL, tz, date);
17207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 5) {
17217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // ISO 8601 extended format
17227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.ISO_EXTENDED_FULL, tz, date);
17237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
17247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // long form, localized GMT pattern
17257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.LOCALIZED_GMT, tz, date);
17267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
17277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                buf.append(result);
17287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
17297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 24: // 'v' - TIMEZONE_GENERIC_FIELD
17307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (count == 1) {
17317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "v"
17327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.GENERIC_SHORT, tz, date);
17337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.METAZONE_SHORT;
17347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 4) {
17357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "vvvv"
17367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.GENERIC_LONG, tz, date);
17377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.METAZONE_LONG;
17387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
17397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            buf.append(result);
17407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
17417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 29: // 'V' - TIMEZONE_SPECIAL_FIELD
17427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (count == 1) {
17437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "V"
17447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.ZONE_ID_SHORT, tz, date);
17457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 2) {
17467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "VV"
17477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.ZONE_ID, tz, date);
17487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 3) {
17497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "VVV"
17507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.EXEMPLAR_LOCATION, tz, date);
17517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 4) {
17527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "VVVV"
17537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.GENERIC_LOCATION, tz, date);
17547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.ZONE_LONG;
17557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
17567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            buf.append(result);
17577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
17587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 31: // 'O' - TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD
17597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (count == 1) {
17607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "O" - Short Localized GMT format
17617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.LOCALIZED_GMT_SHORT, tz, date);
17627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 4) {
17637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "OOOO" - Localized GMT format
17647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.LOCALIZED_GMT, tz, date);
17657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
17667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            buf.append(result);
17677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
17687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 32: // 'X' - TIMEZONE_ISO_FIELD
17697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (count == 1) {
17707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "X" - ISO Basic/Short
17717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.ISO_BASIC_SHORT, tz, date);
17727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 2) {
17737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "XX" - ISO Basic/Fixed
17747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.ISO_BASIC_FIXED, tz, date);
17757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 3) {
17767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "XXX" - ISO Extended/Fixed
17777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.ISO_EXTENDED_FIXED, tz, date);
17787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 4) {
17797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "XXXX" - ISO Basic/Optional second field
17807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.ISO_BASIC_FULL, tz, date);
17817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 5) {
17827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "XXXXX" - ISO Extended/Optional second field
17837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.ISO_EXTENDED_FULL, tz, date);
17847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
17857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            buf.append(result);
17867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
17877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 33: // 'x' - TIMEZONE_ISO_LOCAL_FIELD
17887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (count == 1) {
17897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "x" - ISO Local Basic/Short
17907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.ISO_BASIC_LOCAL_SHORT, tz, date);
17917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 2) {
17927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "x" - ISO Local Basic/Fixed
17937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.ISO_BASIC_LOCAL_FIXED, tz, date);
17947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 3) {
17957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "xxx" - ISO Local Extended/Fixed
17967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.ISO_EXTENDED_LOCAL_FIXED, tz, date);
17977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 4) {
17987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "xxxx" - ISO Local Basic/Optional second field
17997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.ISO_BASIC_LOCAL_FULL, tz, date);
18007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 5) {
18017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // "xxxxx" - ISO Local Extended/Optional second field
18027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                result = tzFormat().format(Style.ISO_EXTENDED_LOCAL_FULL, tz, date);
18037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
18047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            buf.append(result);
18057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
18067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
18077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 25: // 'c' - STANDALONE DAY (use DOW_LOCAL for numeric, DAY_OF_WEEK for standalone)
18087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (count < 3) {
18097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                zeroPaddingNumber(currentNumberFormat,buf, value, 1, maxIntCount);
18107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                break;
18117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
18127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // For alpha day-of-week, we don't want DOW_LOCAL,
18137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // we need the standard DAY_OF_WEEK.
18147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            value = cal.get(Calendar.DAY_OF_WEEK);
18157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (count == 5) {
18167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                safeAppend(formatData.standaloneNarrowWeekdays, value, buf);
18177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_NARROW;
18187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 4) {
18197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                safeAppend(formatData.standaloneWeekdays, value, buf);
18207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_STANDALONE;
18217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 6 && formatData.standaloneShorterWeekdays != null) {
18227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                safeAppend(formatData.standaloneShorterWeekdays, value, buf);
18237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_STANDALONE;
18247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else { // count == 3
18257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                safeAppend(formatData.standaloneShortWeekdays, value, buf);
18267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                capContextUsageType = DateFormatSymbols.CapitalizationContextUsage.DAY_STANDALONE;
18277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
18287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
18297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 27: // 'Q' - QUARTER
18307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (count >= 4) {
18317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                safeAppend(formatData.quarters, value/3, buf);
18327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 3) {
18337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                safeAppend(formatData.shortQuarters, value/3, buf);
18347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
18357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                zeroPaddingNumber(currentNumberFormat,buf, (value/3)+1, count, maxIntCount);
18367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
18377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
18387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case 28: // 'q' - STANDALONE QUARTER
18397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (count >= 4) {
18407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                safeAppend(formatData.standaloneQuarters, value/3, buf);
18417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (count == 3) {
18427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                safeAppend(formatData.standaloneShortQuarters, value/3, buf);
18437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
18447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                zeroPaddingNumber(currentNumberFormat,buf, (value/3)+1, count, maxIntCount);
18457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
18467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
1847bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        case 35: // TIME SEPARATOR (no pattern character currently defined, we should
1848bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                 // not get here but leave support in for future definition.
1849f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            buf.append(formatData.getTimeSeparatorString());
1850f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            break;
18517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        default:
18527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // case 3: // 'd' - DATE
18537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // case 5: // 'H' - HOUR_OF_DAY (0..23)
18547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // case 6: // 'm' - MINUTE
18557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // case 7: // 's' - SECOND
18567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // case 10: // 'D' - DAY_OF_YEAR
18577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // case 11: // 'F' - DAY_OF_WEEK_IN_MONTH
18587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // case 12: // 'w' - WEEK_OF_YEAR
18597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // case 13: // 'W' - WEEK_OF_MONTH
18607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // case 16: // 'K' - HOUR (0..11)
18617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // case 20: // 'u' - EXTENDED_YEAR
18627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // case 21: // 'g' - JULIAN_DAY
18637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // case 22: // 'A' - MILLISECONDS_IN_DAY
18647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
18657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            zeroPaddingNumber(currentNumberFormat,buf, value, count, maxIntCount);
18667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
18677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } // switch (patternCharIndex)
18687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
18697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (fieldNum == 0 && capitalizationContext != null && UCharacter.isLowerCase(buf.codePointAt(bufstart))) {
18707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            boolean titlecase = false;
18717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            switch (capitalizationContext) {
18727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                case CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE:
18737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    titlecase = true;
18747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
18757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                case CAPITALIZATION_FOR_UI_LIST_OR_MENU:
18767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                case CAPITALIZATION_FOR_STANDALONE:
18777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (formatData.capitalization != null) {
18787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        boolean[] transforms = formatData.capitalization.get(capContextUsageType);
18797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        titlecase = (capitalizationContext==DisplayContext.CAPITALIZATION_FOR_UI_LIST_OR_MENU)?
18807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    transforms[0]: transforms[1];
18817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
18827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
18837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                default:
18847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                   break;
18857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
18867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (titlecase) {
18877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (capitalizationBrkIter == null) {
18887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // should only happen when deserializing, etc.
18897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    capitalizationBrkIter = BreakIterator.getSentenceInstance(locale);
18907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
18917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                String firstField = buf.substring(bufstart); // bufstart or beginOffset, should be the same
18927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                String firstFieldTitleCase = UCharacter.toTitleCase(locale, firstField, capitalizationBrkIter,
18937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                                     UCharacter.TITLECASE_NO_LOWERCASE | UCharacter.TITLECASE_NO_BREAK_ADJUSTMENT);
18947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                buf.replace(bufstart, buf.length(), firstFieldTitleCase);
18957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
18967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
18977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
18987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Set the FieldPosition (for the first occurrence only)
18997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (pos.getBeginIndex() == pos.getEndIndex()) {
19007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (pos.getField() == PATTERN_INDEX_TO_DATE_FORMAT_FIELD[patternCharIndex]) {
19017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                pos.setBeginIndex(beginOffset);
19027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                pos.setEndIndex(beginOffset + buf.length() - bufstart);
19037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (pos.getFieldAttribute() ==
19047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                       PATTERN_INDEX_TO_DATE_FORMAT_ATTRIBUTE[patternCharIndex]) {
19057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                pos.setBeginIndex(beginOffset);
19067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                pos.setEndIndex(beginOffset + buf.length() - bufstart);
19077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
19087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
19097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
19107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
19117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static void safeAppend(String[] array, int value, StringBuffer appendTo) {
19127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (array != null && value >= 0 && value < array.length) {
19137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            appendTo.append(array[value]);
19147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
19157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
19167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
19177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static void safeAppendWithMonthPattern(String[] array, int value, StringBuffer appendTo, String monthPattern) {
19187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (array != null && value >= 0 && value < array.length) {
19197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (monthPattern == null) {
19207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                appendTo.append(array[value]);
19217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
19227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                appendTo.append(MessageFormat.format(monthPattern, array[value]));
19237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
19247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
19257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
19267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
19277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
19287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * PatternItem store parsed date/time field pattern information.
19297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
19307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static class PatternItem {
19317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        final char type;
19327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        final int length;
19337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        final boolean isNumeric;
19347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
19357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        PatternItem(char type, int length) {
19367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            this.type = type;
19377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            this.length = length;
19387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            isNumeric = isNumeric(type, length);
19397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
19407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
19417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
19427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static ICUCache<String, Object[]> PARSED_PATTERN_CACHE =
19437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        new SimpleCache<String, Object[]>();
19447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private transient Object[] patternItems;
19457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
19467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
19477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Returns parsed pattern items.  Each item is either String or
19487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * PatternItem.
19497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
19507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private Object[] getPatternItems() {
19517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (patternItems != null) {
19527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return patternItems;
19537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
19547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
19557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        patternItems = PARSED_PATTERN_CACHE.get(pattern);
19567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (patternItems != null) {
19577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return patternItems;
19587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
19597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
19607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        boolean isPrevQuote = false;
19617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        boolean inQuote = false;
19627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        StringBuilder text = new StringBuilder();
19637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        char itemType = 0;  // 0 for string literal, otherwise date/time pattern character
19647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int itemLength = 1;
19657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
19667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        List<Object> items = new ArrayList<Object>();
19677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
19687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (int i = 0; i < pattern.length(); i++) {
19697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            char ch = pattern.charAt(i);
19707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (ch == '\'') {
19717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (isPrevQuote) {
19727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    text.append('\'');
19737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    isPrevQuote = false;
19747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
19757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    isPrevQuote = true;
19767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (itemType != 0) {
19777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        items.add(new PatternItem(itemType, itemLength));
19787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        itemType = 0;
19797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
19807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
19817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                inQuote = !inQuote;
19827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
19837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                isPrevQuote = false;
19847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (inQuote) {
19857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    text.append(ch);
19867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
1987f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                    if (isSyntaxChar(ch)) {
19887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // a date/time pattern character
19897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        if (ch == itemType) {
19907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            itemLength++;
19917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        } else {
19927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            if (itemType == 0) {
19937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                if (text.length() > 0) {
19947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    items.add(text.toString());
19957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    text.setLength(0);
19967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                }
19977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            } else {
19987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                items.add(new PatternItem(itemType, itemLength));
19997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            }
20007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            itemType = ch;
20017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            itemLength = 1;
20027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
20037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    } else {
20047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // a string literal
20057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        if (itemType != 0) {
20067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            items.add(new PatternItem(itemType, itemLength));
20077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            itemType = 0;
20087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
20097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        text.append(ch);
20107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
20117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
20127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
20137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
20147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // handle last item
20157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (itemType == 0) {
20167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (text.length() > 0) {
20177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                items.add(text.toString());
20187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                text.setLength(0);
20197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
20207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
20217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            items.add(new PatternItem(itemType, itemLength));
20227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
20237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
20247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        patternItems = items.toArray(new Object[items.size()]);
20257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
20267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        PARSED_PATTERN_CACHE.put(pattern, patternItems);
20277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
20287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return patternItems;
20297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
20307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
20317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
20327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Internal high-speed method.  Reuses a StringBuffer for results
20337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * instead of creating a String on the heap for each call.
20347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @internal
20357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @deprecated This API is ICU internal only.
20367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
20377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Deprecated
20387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected void zeroPaddingNumber(NumberFormat nf,StringBuffer buf, int value,
20397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                     int minDigits, int maxDigits) {
20407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Note: Indian calendar uses negative value for a calendar
20417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // field. fastZeroPaddingNumber cannot handle negative numbers.
20427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // BTW, it looks like a design bug in the Indian calendar...
20437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (useLocalZeroPaddingNumberFormat && value >= 0) {
20447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            fastZeroPaddingNumber(buf, value, minDigits, maxDigits);
20457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
20467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            nf.setMinimumIntegerDigits(minDigits);
20477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            nf.setMaximumIntegerDigits(maxDigits);
20487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            nf.format(value, buf, new FieldPosition(-1));
20497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
20507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
20517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
20527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
20537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Overrides superclass method and
20547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * This method also clears per field NumberFormat instances
20557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * previously set by {@link #setNumberFormat(String, NumberFormat)}
20567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
20577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
20587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
20597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setNumberFormat(NumberFormat newNumberFormat) {
20607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Override this method to update local zero padding number formatter
20617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        super.setNumberFormat(newNumberFormat);
20627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        initLocalZeroPaddingNumberFormat();
20637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        initializeTimeZoneFormat(true);
20647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
20657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (numberFormatters != null) {
20667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            numberFormatters = null;
20677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
20687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (overrideMap != null) {
20697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            overrideMap = null;
20707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
20717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
20727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2073f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    /*
2074f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * Initializes transient fields for fast simple numeric formatting
2075f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * code. This method should be called whenever number format is updated.
2076f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     */
20777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private void initLocalZeroPaddingNumberFormat() {
20787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (numberFormat instanceof DecimalFormat) {
20797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            decDigits = ((DecimalFormat)numberFormat).getDecimalFormatSymbols().getDigits();
20807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            useLocalZeroPaddingNumberFormat = true;
20817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else if (numberFormat instanceof DateNumberFormat) {
20827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            decDigits = ((DateNumberFormat)numberFormat).getDigits();
20837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            useLocalZeroPaddingNumberFormat = true;
20847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
20857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            useLocalZeroPaddingNumberFormat = false;
20867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
20877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
20887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (useLocalZeroPaddingNumberFormat) {
2089f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            decimalBuf = new char[DECIMAL_BUF_SIZE];
20907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
20917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
20927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
20937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // If true, use local version of zero padding number format
20947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private transient boolean useLocalZeroPaddingNumberFormat;
2095f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    private transient char[] decDigits;     // read-only - can be shared by multiple instances
2096f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    private transient char[] decimalBuf;    // mutable - one per instance
2097f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    private static final int DECIMAL_BUF_SIZE = 10; // sufficient for int numbers
20987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
20997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
21007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Lightweight zero padding integer number format function.
21017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
21027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Note: This implementation is almost equivalent to format method in DateNumberFormat.
21037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * In the method zeroPaddingNumber above should be able to use the one in DateNumberFormat,
21047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * but, it does not help IBM J9's JIT to optimize the performance much.  In simple repeative
21057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * date format test case, having local implementation is ~10% faster than using one in
21067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * DateNumberFormat on IBM J9 VM.  On Sun Hotspot VM, I do not see such difference.
21077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
21087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * -Yoshito
21097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
21107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private void fastZeroPaddingNumber(StringBuffer buf, int value, int minDigits, int maxDigits) {
21117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int limit = decimalBuf.length < maxDigits ? decimalBuf.length : maxDigits;
21127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int index = limit - 1;
21137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        while (true) {
21147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            decimalBuf[index] = decDigits[(value % 10)];
21157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            value /= 10;
21167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (index == 0 || value == 0) {
21177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                break;
21187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
21197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            index--;
21207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
21217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int padding = minDigits - (limit - index);
21227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        while (padding > 0 && index > 0) {
21237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            decimalBuf[--index] = decDigits[0];
21247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            padding--;
21257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
21267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        while (padding > 0) {
21277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // when pattern width is longer than decimalBuf, need extra
21287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // leading zeros - ticke#7595
21297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            buf.append(decDigits[0]);
21307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            padding--;
21317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
21327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        buf.append(decimalBuf, index, limit - index);
21337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
21347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
21357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
21367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Formats a number with the specified minimum and maximum number of digits.
21377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
21387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
21397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected String zeroPaddingNumber(long value, int minDigits, int maxDigits)
21407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
21417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        numberFormat.setMinimumIntegerDigits(minDigits);
21427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        numberFormat.setMaximumIntegerDigits(maxDigits);
21437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return numberFormat.format(value);
21447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
21457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
21467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
2147bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     * Format characters that indicate numeric fields always.
2148bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     */
2149bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    private static final String NUMERIC_FORMAT_CHARS = "ADdFgHhKkmrSsuWwYy";
2150bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
2151bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    /**
2152bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     * Format characters that indicate numeric fields when pattern lengh
2153bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     * is up to 2.
21547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
2155bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    private static final String NUMERIC_FORMAT_CHARS2 = "ceLMQq";
21567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
21577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
21587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Return true if the given format character, occuring count
21597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * times, represents a numeric field.
21607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
21617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final boolean isNumeric(char formatChar, int count) {
2162bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        return NUMERIC_FORMAT_CHARS.indexOf(formatChar) >= 0
2163bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                || (count <= 2 && NUMERIC_FORMAT_CHARS2.indexOf(formatChar) >= 0);
21647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
21657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
21667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
21677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Overrides DateFormat
21687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @see DateFormat
21697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
21707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
21717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void parse(String text, Calendar cal, ParsePosition parsePos)
21727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
21737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        TimeZone backupTZ = null;
21747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Calendar resultCal = null;
21757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (cal != calendar && !cal.getType().equals(calendar.getType())) {
21767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Different calendar type
21777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // We use the time/zone from the input calendar, but
21787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // do not use the input calendar for field calculation.
21797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            calendar.setTimeInMillis(cal.getTimeInMillis());
21807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            backupTZ = calendar.getTimeZone();
21817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            calendar.setTimeZone(cal.getTimeZone());
21827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            resultCal = cal;
21837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            cal = calendar;
21847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
21857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
21867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int pos = parsePos.getIndex();
21877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if(pos < 0) {
21887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            parsePos.setErrorIndex(0);
21897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return;
21907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
21917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int start = pos;
21927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
21937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Output<TimeType> tzTimeType = new Output<TimeType>(TimeType.UNKNOWN);
21947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        boolean[] ambiguousYear = { false };
21957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
21967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // item index for the first numeric field within a contiguous numeric run
21977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int numericFieldStart = -1;
21987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // item length for the first numeric field within a contiguous numeric run
21997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int numericFieldLength = 0;
22007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // start index of numeric text run in the input text
22017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int numericStartPos = 0;
22027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
22037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        MessageFormat numericLeapMonthFormatter = null;
22047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (formatData.leapMonthPatterns != null && formatData.leapMonthPatterns.length >= DateFormatSymbols.DT_MONTH_PATTERN_COUNT) {
22057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            numericLeapMonthFormatter = new MessageFormat(formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_NUMERIC], locale);
22067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
22077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
22087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Object[] items = getPatternItems();
22097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int i = 0;
22107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        while (i < items.length) {
22117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (items[i] instanceof PatternItem) {
22127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // Handle pattern field
22137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                PatternItem field = (PatternItem)items[i];
22147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (field.isNumeric) {
22157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Handle fields within a run of abutting numeric fields.  Take
22167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // the pattern "HHmmss" as an example. We will try to parse
22177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // 2/2/2 characters of the input text, then if that fails,
22187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // 1/2/2.  We only adjust the width of the leftmost field; the
22197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // others remain fixed.  This allows "123456" => 12:34:56, but
22207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // "12345" => 1:23:45.  Likewise, for the pattern "yyyyMMdd" we
22217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // try 4/2/2, 3/2/2, 2/2/2, and finally 1/2/2.
22227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (numericFieldStart == -1) {
22237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // check if this field is followed by abutting another numeric field
22247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        if ((i + 1) < items.length
22257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                && (items[i + 1] instanceof PatternItem)
22267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                && ((PatternItem)items[i + 1]).isNumeric) {
22277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            // record the first numeric field within a numeric text run
22287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            numericFieldStart = i;
22297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            numericFieldLength = field.length;
22307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            numericStartPos = pos;
22317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
22327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
22337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
22347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (numericFieldStart != -1) {
22357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Handle a numeric field within abutting numeric fields
22367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    int len = field.length;
22377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (numericFieldStart == i) {
22387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        len = numericFieldLength;
22397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
22407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
22417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Parse a numeric field
22427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    pos = subParse(text, pos, field.type, len,
22437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            true, false, ambiguousYear, cal, numericLeapMonthFormatter, tzTimeType);
22447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
22457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (pos < 0) {
22467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // If the parse fails anywhere in the numeric run, back up to the
22477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // start of the run and use shorter pattern length for the first
22487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // numeric field.
22497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        --numericFieldLength;
22507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        if (numericFieldLength == 0) {
22517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            // can not make shorter any more
22527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            parsePos.setIndex(start);
22537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            parsePos.setErrorIndex(pos);
22547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            if (backupTZ != null) {
22557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                calendar.setTimeZone(backupTZ);
22567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            }
22577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            return;
22587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
22597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        i = numericFieldStart;
22607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        pos = numericStartPos;
22617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        continue;
22627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
22637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
22647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else if (field.type != 'l') { // (SMALL LETTER L) obsolete pattern char just gets ignored
22657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Handle a non-numeric field or a non-abutting numeric field
22667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    numericFieldStart = -1;
22677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
22687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    int s = pos;
22697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    pos = subParse(text, pos, field.type, field.length,
22707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            false, true, ambiguousYear, cal, numericLeapMonthFormatter, tzTimeType);
22717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
22727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (pos < 0) {
22737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        if (pos == ISOSpecialEra) {
22747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            // era not present, in special cases allow this to continue
22757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            pos = s;
22767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
22777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            if (i+1 < items.length) {
22787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
22797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                String patl = null;
22807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                // if it will cause a class cast exception to String, we can't use it
22817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                try {
22827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    patl = (String)items[i+1];
22837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                } catch(ClassCastException cce) {
22847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    parsePos.setIndex(start);
22857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    parsePos.setErrorIndex(s);
22867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    if (backupTZ != null) {
22877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        calendar.setTimeZone(backupTZ);
22887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    }
22897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    return;
22907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                }
22917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
22927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                // get next item in pattern
22937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                if(patl == null)
22947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    patl = (String)items[i+1];
22957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                int plen = patl.length();
22967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                int idx=0;
22977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
22987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                // White space characters found in patten.
22997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                // Skip contiguous white spaces.
23007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                while (idx < plen) {
23017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
23027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    char pch = patl.charAt(idx);
23037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    if (PatternProps.isWhiteSpace(pch))
23047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        idx++;
23057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    else
23067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        break;
23077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                }
23087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
23097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                // if next item in pattern is all whitespace, skip it
23107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                if (idx == plen) {
23117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    i++;
23127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                }
23137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
23147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            }
23157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        } else {
23167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            parsePos.setIndex(start);
23177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            parsePos.setErrorIndex(s);
23187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            if (backupTZ != null) {
23197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                calendar.setTimeZone(backupTZ);
23207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            }
23217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            return;
23227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
23237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
2324f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
23257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
23267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
23277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // Handle literal pattern text literal
23287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                numericFieldStart = -1;
23297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                boolean[] complete = new boolean[1];
23307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                pos = matchLiteral(text, pos, items, i, complete);
23317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (!complete[0]) {
23327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Set the position of mismatch
23337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    parsePos.setIndex(start);
23347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    parsePos.setErrorIndex(pos);
23357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (backupTZ != null) {
23367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        calendar.setTimeZone(backupTZ);
23377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
23387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return;
23397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
23407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
23417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            ++i;
23427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
23437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
23447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Special hack for trailing "." after non-numeric field.
23457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (pos < text.length()) {
23467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            char extra = text.charAt(pos);
23477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (extra == '.' && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_WHITESPACE) && items.length != 0) {
23487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // only do if the last field is not numeric
23497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                Object lastItem = items[items.length - 1];
23507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (lastItem instanceof PatternItem && !((PatternItem)lastItem).isNumeric) {
23517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    pos++; // skip the extra "."
23527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
23537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
23547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
23557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
23567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // At this point the fields of Calendar have been set.  Calendar
23577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // will fill in default values for missing fields when the time
23587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // is computed.
23597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
23607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        parsePos.setIndex(pos);
23617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
23627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // This part is a problem:  When we call parsedDate.after, we compute the time.
23637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Take the date April 3 2004 at 2:30 am.  When this is first set up, the year
23647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // will be wrong if we're parsing a 2-digit year pattern.  It will be 1904.
23657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // April 3 1904 is a Sunday (unlike 2004) so it is the DST onset day.  2:30 am
23667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // is therefore an "impossible" time, since the time goes from 1:59 to 3:00 am
23677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // on that day.  It is therefore parsed out to fields as 3:30 am.  Then we
23687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // add 100 years, and get April 3 2004 at 3:30 am.  Note that April 3 2004 is
23697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // a Saturday, so it can have a 2:30 am -- and it should. [LIU]
23707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /*
23717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          Date parsedDate = cal.getTime();
23727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          if( ambiguousYear[0] && !parsedDate.after(getDefaultCenturyStart()) ) {
23737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          cal.add(Calendar.YEAR, 100);
23747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          parsedDate = cal.getTime();
23757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          }
23767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        */
23777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Because of the above condition, save off the fields in case we need to readjust.
23787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // The procedure we use here is not particularly efficient, but there is no other
23797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // way to do this given the API restrictions present in Calendar.  We minimize
23807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // inefficiency by only performing this computation when it might apply, that is,
23817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // when the two-digit year is equal to the start year, and thus might fall at the
23827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // front or the back of the default century.  This only works because we adjust
23837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // the year correctly to start with in other cases -- see subParse().
23847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        try {
23857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            TimeType tztype = tzTimeType.value;
23867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (ambiguousYear[0] || tztype != TimeType.UNKNOWN) {
23877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // We need a copy of the fields, and we need to avoid triggering a call to
23887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // complete(), which will recalculate the fields.  Since we can't access
23897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // the fields[] array in Calendar, we clone the entire object.  This will
23907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // stop working if Calendar.clone() is ever rewritten to call complete().
23917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                Calendar copy;
23927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (ambiguousYear[0]) { // the two-digit year == the default start year
23937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    copy = (Calendar)cal.clone();
23947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    Date parsedDate = copy.getTime();
23957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (parsedDate.before(getDefaultCenturyStart())) {
23967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // We can't use add here because that does a complete() first.
23977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        cal.set(Calendar.YEAR, getDefaultCenturyStartYear() + 100);
23987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
23997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
24007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (tztype != TimeType.UNKNOWN) {
24017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    copy = (Calendar)cal.clone();
24027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    TimeZone tz = copy.getTimeZone();
24037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    BasicTimeZone btz = null;
24047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (tz instanceof BasicTimeZone) {
24057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        btz = (BasicTimeZone)tz;
24067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
24077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
24087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Get local millis
24097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    copy.set(Calendar.ZONE_OFFSET, 0);
24107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    copy.set(Calendar.DST_OFFSET, 0);
24117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    long localMillis = copy.getTimeInMillis();
24127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
24137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Make sure parsed time zone type (Standard or Daylight)
24147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // matches the rule used by the parsed time zone.
24157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    int[] offsets = new int[2];
24167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (btz != null) {
24177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        if (tztype == TimeType.STANDARD) {
24187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            btz.getOffsetFromLocal(localMillis,
24197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    BasicTimeZone.LOCAL_STD, BasicTimeZone.LOCAL_STD, offsets);
24207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        } else {
24217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            btz.getOffsetFromLocal(localMillis,
24227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    BasicTimeZone.LOCAL_DST, BasicTimeZone.LOCAL_DST, offsets);
24237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
24247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    } else {
24257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // No good way to resolve ambiguous time at transition,
24267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // but following code work in most case.
24277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        tz.getOffset(localMillis, true, offsets);
24287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
24297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        if (tztype == TimeType.STANDARD && offsets[1] != 0
24307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            || tztype == TimeType.DAYLIGHT && offsets[1] == 0) {
24317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            // Roll back one day and try it again.
24327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            // Note: This code assumes 1. timezone transition only happens
24337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            // once within 24 hours at max
24347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            // 2. the difference of local offsets at the transition is
24357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            // less than 24 hours.
24367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            tz.getOffset(localMillis - (24*60*60*1000), true, offsets);
24377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
24387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
24397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
24407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Now, compare the results with parsed type, either standard or
24417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // daylight saving time
24427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    int resolvedSavings = offsets[1];
24437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (tztype == TimeType.STANDARD) {
24447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        if (offsets[1] != 0) {
24457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            // Override DST_OFFSET = 0 in the result calendar
24467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            resolvedSavings = 0;
24477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
24487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    } else { // tztype == TZTYPE_DST
24497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        if (offsets[1] == 0) {
24507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            if (btz != null) {
24517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                long time = localMillis + offsets[0];
24527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                // We use the nearest daylight saving time rule.
24537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                TimeZoneTransition beforeTrs, afterTrs;
24547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                long beforeT = time, afterT = time;
24557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                int beforeSav = 0, afterSav = 0;
24567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
24577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                // Search for DST rule before or on the time
24587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                while (true) {
24597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    beforeTrs = btz.getPreviousTransition(beforeT, true);
24607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    if (beforeTrs == null) {
24617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        break;
24627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    }
24637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    beforeT = beforeTrs.getTime() - 1;
24647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    beforeSav = beforeTrs.getFrom().getDSTSavings();
24657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    if (beforeSav != 0) {
24667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        break;
24677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    }
24687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                }
24697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
24707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                // Search for DST rule after the time
24717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                while (true) {
24727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    afterTrs = btz.getNextTransition(afterT, false);
24737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    if (afterTrs == null) {
24747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        break;
24757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    }
24767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    afterT = afterTrs.getTime();
24777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    afterSav = afterTrs.getTo().getDSTSavings();
24787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    if (afterSav != 0) {
24797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        break;
24807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    }
24817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                }
24827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
24837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                if (beforeTrs != null && afterTrs != null) {
24847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    if (time - beforeT > afterT - time) {
24857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        resolvedSavings = afterSav;
24867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    } else {
24877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        resolvedSavings = beforeSav;
24887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    }
24897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                } else if (beforeTrs != null && beforeSav != 0) {
24907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    resolvedSavings = beforeSav;
24917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                } else if (afterTrs != null && afterSav != 0) {
24927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    resolvedSavings = afterSav;
24937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                } else {
24947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    resolvedSavings = btz.getDSTSavings();
24957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                }
24967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            } else {
24977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                resolvedSavings = tz.getDSTSavings();
24987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            }
24997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            if (resolvedSavings == 0) {
25007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                // Final fallback
25017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                resolvedSavings = millisPerHour;
25027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            }
25037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
25047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
25057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    cal.set(Calendar.ZONE_OFFSET, offsets[0]);
25067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    cal.set(Calendar.DST_OFFSET, resolvedSavings);
25077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
25087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
25097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
25107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // An IllegalArgumentException will be thrown by Calendar.getTime()
25117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // if any fields are out of range, e.g., MONTH == 17.
25127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        catch (IllegalArgumentException e) {
25137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            parsePos.setErrorIndex(pos);
25147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            parsePos.setIndex(start);
25157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (backupTZ != null) {
25167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                calendar.setTimeZone(backupTZ);
25177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
25187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return;
25197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
25207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Set the parsed result if local calendar is used
25217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // instead of the input calendar
25227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (resultCal != null) {
25237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            resultCal.setTimeZone(cal.getTimeZone());
25247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            resultCal.setTimeInMillis(cal.getTimeInMillis());
25257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
25267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Restore the original time zone if required
25277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (backupTZ != null) {
25287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            calendar.setTimeZone(backupTZ);
25297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
25307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
25317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
25327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
25337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Matches text (starting at pos) with patl. Returns the new pos, and sets complete[0]
25347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * if it matched the entire text. Whitespace sequences are treated as singletons.
25357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <p>If isLenient and if we fail to match the first time, some special hacks are put into place.
25367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <ul><li>we are between date and time fields, then one or more whitespace characters
25377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * in the text are accepted instead.</li>
25387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * <ul><li>we are after a non-numeric field, and the text starts with a ".", we skip it.</li>
25397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * </ul>
25407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
25417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int matchLiteral(String text, int pos, Object[] items, int itemIndex, boolean[] complete) {
25427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int originalPos = pos;
25437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String patternLiteral = (String)items[itemIndex];
25447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int plen = patternLiteral.length();
25457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int tlen = text.length();
25467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int idx = 0;
25477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        while (idx < plen && pos < tlen) {
25487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            char pch = patternLiteral.charAt(idx);
25497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            char ich = text.charAt(pos);
25507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (PatternProps.isWhiteSpace(pch)
25517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                && PatternProps.isWhiteSpace(ich)) {
25527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // White space characters found in both patten and input.
25537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // Skip contiguous white spaces.
25547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                while ((idx + 1) < plen &&
25557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        PatternProps.isWhiteSpace(patternLiteral.charAt(idx + 1))) {
25567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                     ++idx;
25577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
25587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                while ((pos + 1) < tlen &&
25597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        PatternProps.isWhiteSpace(text.charAt(pos + 1))) {
25607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                     ++pos;
25617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
25627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else if (pch != ich) {
25637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (ich == '.' && pos == originalPos && 0 < itemIndex && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_WHITESPACE)) {
25647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    Object before = items[itemIndex-1];
25657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (before instanceof PatternItem) {
25667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        boolean isNumeric = ((PatternItem) before).isNumeric;
25677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        if (!isNumeric) {
25687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            ++pos; // just update pos
25697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            continue;
25707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
25717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
25727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else if ((pch == ' ' || pch == '.') && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_WHITESPACE)) {
25737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    ++idx;
25747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    continue;
2575bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                } else if (pos != originalPos && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_PARTIAL_LITERAL_MATCH)) {
25767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    ++idx;
25777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    continue;
25787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
25797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                break;
25807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
25817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            ++idx;
25827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            ++pos;
25837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
25847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        complete[0] = idx == plen;
25857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (complete[0] == false && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_WHITESPACE) && 0 < itemIndex && itemIndex < items.length - 1) {
25867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // If fully lenient, accept " "* for any text between a date and a time field
25877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // We don't go more lenient, because we don't want to accept "12/31" for "12:31".
25887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // People may be trying to parse for a date, then for a time.
25897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (originalPos < tlen) {
25907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                Object before = items[itemIndex-1];
25917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                Object after = items[itemIndex+1];
25927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (before instanceof PatternItem && after instanceof PatternItem) {
25937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    char beforeType = ((PatternItem) before).type;
25947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    char afterType = ((PatternItem) after).type;
25957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (DATE_PATTERN_TYPE.contains(beforeType) != DATE_PATTERN_TYPE.contains(afterType)) {
25967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        int newPos = originalPos;
25977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        while (true) {
25987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            char ich = text.charAt(newPos);
25997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            if (!PatternProps.isWhiteSpace(ich)) {
26007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                break;
26017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            }
26027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            ++newPos;
26037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
26047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        complete[0] = newPos > originalPos;
26057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        pos = newPos;
26067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
26077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
26087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
26097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
26107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return pos;
26117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
26127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
26137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static final UnicodeSet DATE_PATTERN_TYPE = new UnicodeSet("[GyYuUQqMLlwWd]").freeze();
26147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
26157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
26167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Attempt to match the text at a given position against an array of
26177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * strings.  Since multiple strings in the array may match (for
26187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * example, if the array contains "a", "ab", and "abc", all will match
26197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * the input string "abcd") the longest match is returned.  As a side
26207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * effect, the given field of <code>cal</code> is set to the index
26217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * of the best match, if there is one.
26227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param text the time text being parsed.
26237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param start where to start parsing.
26247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param field the date field being parsed.
26257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param data the string array to parsed.
26267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param cal
26277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return the new start position if matching succeeded; a negative
26287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * number indicating matching failure, otherwise.  As a side effect,
26297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * sets the <code>cal</code> field <code>field</code> to the index
26307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * of the best match, if matching succeeded.
26317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
26327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
26337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected int matchString(String text, int start, int field, String[] data, Calendar cal)
26347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
26357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return matchString(text, start, field, data, null, cal);
26367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
26377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
26387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
26397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Attempt to match the text at a given position against an array of
26407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * strings.  Since multiple strings in the array may match (for
26417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * example, if the array contains "a", "ab", and "abc", all will match
26427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * the input string "abcd") the longest match is returned.  As a side
26437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * effect, the given field of <code>cal</code> is set to the index
26447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * of the best match, if there is one.
26457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param text the time text being parsed.
26467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param start where to start parsing.
26477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param field the date field being parsed.
26487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param data the string array to parsed.
26497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param monthPattern leap month pattern, or null if none.
26507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param cal
26517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return the new start position if matching succeeded; a negative
26527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * number indicating matching failure, otherwise.  As a side effect,
26537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * sets the <code>cal</code> field <code>field</code> to the index
26547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * of the best match, if matching succeeded.
26557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @internal
26567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @deprecated This API is ICU internal only.
26577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
26587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Deprecated
26597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int matchString(String text, int start, int field, String[] data, String monthPattern, Calendar cal)
26607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
26617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int i = 0;
26627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int count = data.length;
26637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
26647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (field == Calendar.DAY_OF_WEEK) i = 1;
26657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
26667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // There may be multiple strings in the data[] array which begin with
26677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
26687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // We keep track of the longest match, and return that.  Note that this
26697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // unfortunately requires us to test all array elements.
26707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int bestMatchLength = 0, bestMatch = -1;
26717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int isLeapMonth = 0;
26727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int matchLength = 0;
26737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
26747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (; i<count; ++i)
26757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            {
26767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                int length = data[i].length();
26777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // Always compare if we have no match yet; otherwise only compare
26787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // against potentially better matches (longer strings).
26797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (length > bestMatchLength &&
26807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    (matchLength = regionMatchesWithOptionalDot(text, start, data[i], length)) >= 0)
26817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    {
26827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        bestMatch = i;
26837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        bestMatchLength = matchLength;
26847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        isLeapMonth = 0;
26857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
26867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (monthPattern != null) {
26877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    String leapMonthName = MessageFormat.format(monthPattern, data[i]);
26887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    length = leapMonthName.length();
26897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (length > bestMatchLength &&
26907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        (matchLength = regionMatchesWithOptionalDot(text, start, leapMonthName, length)) >= 0)
26917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        {
26927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            bestMatch = i;
26937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            bestMatchLength = matchLength;
26947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            isLeapMonth = 1;
26957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
26967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                 }
26977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
26987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (bestMatch >= 0)
26997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            {
2700f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                if (field >= 0) {
2701f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                    if (field == Calendar.YEAR) {
2702f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                        bestMatch++; // only get here for cyclic year names, which match 1-based years 1-60
2703f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                    }
2704f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                    cal.set(field, bestMatch);
2705f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                    if (monthPattern != null) {
2706f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                        cal.set(Calendar.IS_LEAP_MONTH, isLeapMonth);
2707f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                    }
27087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
27097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return start + bestMatchLength;
27107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
27117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return ~start;
27127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
27137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
27147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int regionMatchesWithOptionalDot(String text, int start, String data, int length) {
27157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        boolean matches = text.regionMatches(true, start, data, 0, length);
27167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (matches) {
27177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return length;
27187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
27197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (data.length() > 0 && data.charAt(data.length()-1) == '.') {
27207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (text.regionMatches(true, start, data, 0, length-1)) {
27217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return length - 1;
27227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
27237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
27247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return -1;
27257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
27267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
27277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
27287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Attempt to match the text at a given position against an array of quarter
27297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * strings.  Since multiple strings in the array may match (for
27307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * example, if the array contains "a", "ab", and "abc", all will match
27317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * the input string "abcd") the longest match is returned.  As a side
27327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * effect, the given field of <code>cal</code> is set to the index
27337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * of the best match, if there is one.
27347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param text the time text being parsed.
27357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param start where to start parsing.
27367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param field the date field being parsed.
27377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param data the string array to parsed.
27387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return the new start position if matching succeeded; a negative
27397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * number indicating matching failure, otherwise.  As a side effect,
27407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * sets the <code>cal</code> field <code>field</code> to the index
27417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * of the best match, if matching succeeded.
27427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
27437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
27447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected int matchQuarterString(String text, int start, int field, String[] data, Calendar cal)
27457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
27467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int i = 0;
27477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int count = data.length;
27487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
27497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // There may be multiple strings in the data[] array which begin with
27507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
27517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // We keep track of the longest match, and return that.  Note that this
27527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // unfortunately requires us to test all array elements.
27537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int bestMatchLength = 0, bestMatch = -1;
27547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int matchLength = 0;
27557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (; i<count; ++i) {
27567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            int length = data[i].length();
27577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Always compare if we have no match yet; otherwise only compare
27587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // against potentially better matches (longer strings).
27597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (length > bestMatchLength &&
27607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                (matchLength = regionMatchesWithOptionalDot(text, start, data[i], length)) >= 0) {
27617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
27627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                bestMatch = i;
27637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                bestMatchLength = matchLength;
27647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
27657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
27667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
27677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (bestMatch >= 0) {
27687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            cal.set(field, bestMatch * 3);
27697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return start + bestMatchLength;
27707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
27717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
27727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return -start;
27737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
27747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
27757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
27767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Protected method that converts one field of the input string into a
27777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * numeric field value in <code>cal</code>.  Returns -start (for
27787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * ParsePosition) if failed.  Subclasses may override this method to
27797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * modify or add parsing capabilities.
27807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param text the time text to be parsed.
27817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param start where to start parsing.
27827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param ch the pattern character for the date field text to be parsed.
27837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param count the count of a pattern character.
27847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param obeyCount if true, then the next field directly abuts this one,
27857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * and we should use the count to know when to stop parsing.
27867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param ambiguousYear return parameter; upon return, if ambiguousYear[0]
27877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * is true, then a two-digit year was parsed and may need to be readjusted.
27887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param cal
27897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return the new start position if matching succeeded; a negative
27907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * number indicating matching failure, otherwise.  As a side effect,
27917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * set the appropriate field of <code>cal</code> with the parsed
27927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * value.
27937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
27947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
27957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected int subParse(String text, int start, char ch, int count,
27967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                           boolean obeyCount, boolean allowNegative,
27977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                           boolean[] ambiguousYear, Calendar cal)
27987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
27997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return subParse(text, start, ch, count, obeyCount, allowNegative, ambiguousYear, cal, null, null);
28007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
28017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
28027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
28037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Protected method that converts one field of the input string into a
28047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * numeric field value in <code>cal</code>.  Returns -start (for
28057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * ParsePosition) if failed.  Subclasses may override this method to
28067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * modify or add parsing capabilities.
28077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param text the time text to be parsed.
28087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param start where to start parsing.
28097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param ch the pattern character for the date field text to be parsed.
28107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param count the count of a pattern character.
28117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param obeyCount if true, then the next field directly abuts this one,
28127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * and we should use the count to know when to stop parsing.
28137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param ambiguousYear return parameter; upon return, if ambiguousYear[0]
28147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * is true, then a two-digit year was parsed and may need to be readjusted.
28157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param cal
28167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param numericLeapMonthFormatter if non-null, used to parse numeric leap months.
28177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param tzTimeType the type of parsed time zone - standard, daylight or unknown (output).
28187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *      This parameter can be null if caller does not need the information.
28197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return the new start position if matching succeeded; a negative
28207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * number indicating matching failure, otherwise.  As a side effect,
28217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * set the appropriate field of <code>cal</code> with the parsed
28227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * value.
28237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @internal
28247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @deprecated This API is ICU internal only.
28257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
28267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Deprecated
28277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @SuppressWarnings("fallthrough")
28287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private int subParse(String text, int start, char ch, int count,
28297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                           boolean obeyCount, boolean allowNegative,
28307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                           boolean[] ambiguousYear, Calendar cal,
28317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                           MessageFormat numericLeapMonthFormatter, Output<TimeType> tzTimeType)
28327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
28337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Number number = null;
28347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        NumberFormat currentNumberFormat = null;
28357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int value = 0;
28367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int i;
28377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        ParsePosition pos = new ParsePosition(0);
28387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2839f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        int patternCharIndex = getIndexFromChar(ch);
28407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (patternCharIndex == -1) {
28417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return ~start;
28427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
28437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
28447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        currentNumberFormat = getNumberFormat(ch);
28457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
2846f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex]; // -1 if irrelevant
28477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
28487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (numericLeapMonthFormatter != null) {
28497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            numericLeapMonthFormatter.setFormatByArgumentIndex(0, currentNumberFormat);
28507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
28517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        boolean isChineseCalendar = ( cal.getType().equals("chinese") || cal.getType().equals("dangi") );
28527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
28537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // If there are any spaces here, skip over them.  If we hit the end
28547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // of the string, then fail.
28557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (;;) {
28567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (start >= text.length()) {
28577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return ~start;
28587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
28597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            int c = UTF16.charAt(text, start);
28607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (!UCharacter.isUWhiteSpace(c) || !PatternProps.isWhiteSpace(c)) {
28617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                break;
28627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
28637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            start += UTF16.getCharCount(c);
28647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
28657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        pos.setIndex(start);
28667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
28677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // We handle a few special cases here where we need to parse
28687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // a number value.  We handle further, more generic cases below.  We need
28697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // to handle some of them here because some fields require extra processing on
28707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // the parsed value.
28717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (patternCharIndex == 4 /*'k' HOUR_OF_DAY1_FIELD*/ ||
28727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            patternCharIndex == 15 /*'h' HOUR1_FIELD*/ ||
28737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            (patternCharIndex == 2 /*'M' MONTH_FIELD*/ && count <= 2) ||
28747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            patternCharIndex == 26 /*'L' STAND_ALONE_MONTH*/ ||
28757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            patternCharIndex == 19 /*'e' DOW_LOCAL*/ ||
28767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            patternCharIndex == 25 /*'c' STAND_ALONE_DAY_OF_WEEK*/ ||
28777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            patternCharIndex == 1 /*'y' YEAR */ || patternCharIndex == 18 /*'Y' YEAR_WOY */ ||
28787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            patternCharIndex == 30 /*'U' YEAR_NAME_FIELD, falls back to numeric */ ||
28797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            (patternCharIndex == 0 /*'G' ERA */ && isChineseCalendar) ||
28807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            patternCharIndex == 27 /* 'Q' - QUARTER*/ ||
28817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            patternCharIndex == 28 /* 'q' - STANDALONE QUARTER*/ ||
28827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            patternCharIndex == 8 /*'S' FRACTIONAL_SECOND */ )
28837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            {
28847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // It would be good to unify this with the obeyCount logic below,
28857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // but that's going to be difficult.
28867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
28877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                boolean parsedNumericLeapMonth = false;
28887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (numericLeapMonthFormatter != null && (patternCharIndex == 2 || patternCharIndex == 26)) {
28897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // First see if we can parse month number with leap month pattern
28907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    Object[] args = numericLeapMonthFormatter.parse(text, pos);
28917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (args != null && pos.getIndex() > start && (args[0] instanceof Number)) {
28927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        parsedNumericLeapMonth = true;
28937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        number = (Number)args[0];
28947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        cal.set(Calendar.IS_LEAP_MONTH, 1);
28957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    } else {
28967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        pos.setIndex(start);
28977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        cal.set(Calendar.IS_LEAP_MONTH, 0);
28987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                   }
28997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
29007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
29017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (!parsedNumericLeapMonth) {
29027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (obeyCount) {
29037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        if ((start+count) > text.length()) {
29047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            return ~start;
29057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
29067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        number = parseInt(text, count, pos, allowNegative,currentNumberFormat);
29077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    } else {
29087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        number = parseInt(text, pos, allowNegative,currentNumberFormat);
29097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
29107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (number == null && !allowNumericFallback(patternCharIndex)) {
29117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // only return if pattern is NOT one that allows numeric fallback
29127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        return ~start;
29137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
29147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
29157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
29167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (number != null) {
29177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    value = number.intValue();
29187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
29197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
29207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
29217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        switch (patternCharIndex)
29227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            {
29237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 0: // 'G' - ERA
29247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if ( isChineseCalendar ) {
29257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Numeric era handling moved from ChineseDateFormat,
29267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // If we didn't have a number, already returned -start above
29277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    cal.set(Calendar.ERA, value);
29287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return pos.getIndex();
29297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
29307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                int ps = 0;
29317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (count == 5) {
29327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    ps = matchString(text, start, Calendar.ERA, formatData.narrowEras, null, cal);
29337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else if (count == 4) {
29347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    ps = matchString(text, start, Calendar.ERA, formatData.eraNames, null, cal);
29357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
29367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    ps = matchString(text, start, Calendar.ERA, formatData.eras, null, cal);
29377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
29387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
29397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // check return position, if it equals -start, then matchString error
29407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // special case the return code so we don't necessarily fail out until we
29417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // verify no year information also
29427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (ps == ~start)
29437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    ps = ISOSpecialEra;
29447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
29457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return ps;
29467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
29477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 1: // 'y' - YEAR
29487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 18: // 'Y' - YEAR_WOY
29497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // If there are 3 or more YEAR pattern characters, this indicates
29507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // that the year value is to be treated literally, without any
29517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // two-digit year adjustments (e.g., from "01" to 2001).  Otherwise
29527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // we made adjustments to place the 2-digit year in the proper
29537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // century, for parsed strings from "00" to "99".  Any other string
29547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // is treated literally:  "2250", "-1", "1", "002".
29557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                /* 'yy' is the only special case, 'y' is interpreted as number. [Richard/GCL]*/
29567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                /* Skip this for Chinese calendar, moved from ChineseDateFormat */
29577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if ( override != null && (override.compareTo("hebr") == 0 || override.indexOf("y=hebr") >= 0) && value < 1000 ) {
29587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
29597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else if (count == 2 && (pos.getIndex() - start) == 2 && cal.haveDefaultCentury()
29607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    && UCharacter.isDigit(text.charAt(start))
29617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    && UCharacter.isDigit(text.charAt(start+1)))
29627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    {
29637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // Assume for example that the defaultCenturyStart is 6/18/1903.
29647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // This means that two-digit years will be forced into the range
29657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // 6/18/1903 to 6/17/2003.  As a result, years 00, 01, and 02
29667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // correspond to 2000, 2001, and 2002.  Years 04, 05, etc. correspond
29677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // to 1904, 1905, etc.  If the year is 03, then it is 2003 if the
29687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // other fields specify a date before 6/18, or 1903 if they specify a
29697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // date afterwards.  As a result, 03 is an ambiguous year.  All other
29707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        // two-digit years are unambiguous.
29717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        int ambiguousTwoDigitYear = getDefaultCenturyStartYear() % 100;
29727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        ambiguousYear[0] = value == ambiguousTwoDigitYear;
29737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        value += (getDefaultCenturyStartYear()/100)*100 +
29747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            (value < ambiguousTwoDigitYear ? 100 : 0);
29757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
29767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                cal.set(field, value);
29777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
29787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // Delayed checking for adjustment of Hebrew month numbers in non-leap years.
29797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (DelayedHebrewMonthCheck) {
29807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (!HebrewCalendar.isLeapYear(value)) {
29817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        cal.add(Calendar.MONTH,1);
29827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
29837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    DelayedHebrewMonthCheck = false;
29847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
29857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return pos.getIndex();
29867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 30: // 'U' - YEAR_NAME_FIELD
29877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (formatData.shortYearNames != null) {
29887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    int newStart = matchString(text, start, Calendar.YEAR, formatData.shortYearNames, null, cal);
29897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (newStart > 0) {
29907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        return newStart;
29917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
29927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
29937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if ( number != null && (getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC) || formatData.shortYearNames == null || value > formatData.shortYearNames.length) ) {
29947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    cal.set(Calendar.YEAR, value);
29957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return pos.getIndex();
29967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
29977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return ~start;
29987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 2: // 'M' - MONTH
29997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 26: // 'L' - STAND_ALONE_MONTH
30007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (count <= 2 || (number != null && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC))) {
30017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // i.e., M/MM, L/LL or lenient & have a number
30027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Don't want to parse the month if it is a string
30037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // while pattern uses numeric style: M/MM, L/LL.
30047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // [We computed 'value' above.]
30057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    cal.set(Calendar.MONTH, value - 1);
30067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // When parsing month numbers from the Hebrew Calendar, we might need
30077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // to adjust the month depending on whether or not it was a leap year.
30087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // We may or may not yet know what year it is, so might have to delay
30097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // checking until the year is parsed.
30107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (cal.getType().equals("hebrew") && value >= 6) {
30117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        if (cal.isSet(Calendar.YEAR)) {
30127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            if (!HebrewCalendar.isLeapYear(cal.get(Calendar.YEAR))) {
30137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                cal.set(Calendar.MONTH, value);
30147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            }
30157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        } else {
30167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            DelayedHebrewMonthCheck = true;
30177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
30187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
30197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return pos.getIndex();
30207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
30217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // count >= 3 // i.e., MMM/MMMM or LLL/LLLL
30227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Want to be able to parse both short and long forms.
30237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    boolean haveMonthPat = (formatData.leapMonthPatterns != null && formatData.leapMonthPatterns.length >= DateFormatSymbols.DT_MONTH_PATTERN_COUNT);
30247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Try count == 4 first:, unless we're strict
30257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    int newStart = 0;
30267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
30277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        newStart = (patternCharIndex == 2)?
30287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            matchString(text, start, Calendar.MONTH, formatData.months,
30297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    (haveMonthPat)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_FORMAT_WIDE]: null, cal):
30307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            matchString(text, start, Calendar.MONTH, formatData.standaloneMonths,
30317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                    (haveMonthPat)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_STANDALONE_WIDE]: null, cal);
30327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (newStart > 0) {
30337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        return newStart;
30347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
30357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
30367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // count == 4 failed, now try count == 3
30377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
30387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        return (patternCharIndex == 2)?
30397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                matchString(text, start, Calendar.MONTH, formatData.shortMonths,
30407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        (haveMonthPat)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_FORMAT_ABBREV]: null, cal):
30417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                matchString(text, start, Calendar.MONTH, formatData.standaloneShortMonths,
30427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        (haveMonthPat)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_STANDALONE_ABBREV]: null, cal);
30437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
30447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return newStart;
30457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
30467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 4: // 'k' - HOUR_OF_DAY (1..24)
30477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // [We computed 'value' above.]
30487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (value == cal.getMaximum(Calendar.HOUR_OF_DAY)+1) {
30497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    value = 0;
30507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
30517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                cal.set(Calendar.HOUR_OF_DAY, value);
30527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return pos.getIndex();
30537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 8: // 'S' - FRACTIONAL_SECOND
30547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // Fractional seconds left-justify
30557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                i = pos.getIndex() - start;
30567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (i < 3) {
30577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    while (i < 3) {
30587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        value *= 10;
30597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        i++;
30607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
30617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
30627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    int a = 1;
30637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    while (i > 3) {
30647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        a *= 10;
30657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        i--;
30667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
30677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    value /= a;
30687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
30697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                cal.set(Calendar.MILLISECOND, value);
30707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return pos.getIndex();
30717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 19: // 'e' - DOW_LOCAL
30727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if(count <= 2 || (number != null && (getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC))) ) {
30737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // i.e. e/ee or lenient and have a number
30747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    cal.set(field, value);
30757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return pos.getIndex();
30767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
30777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // else for eee-eeeeee, fall through to EEE-EEEEEE handling
30787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                //$FALL-THROUGH$
30797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 9: { // 'E' - DAY_OF_WEEK
30807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // Want to be able to parse at least wide, abbrev, short, and narrow forms.
30817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                int newStart = 0;
30827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
30837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if ((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.weekdays, null, cal)) > 0) { // try EEEE wide
30847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        return newStart;
30857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
30867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
30877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
30887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if ((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.shortWeekdays, null, cal)) > 0) { // try EEE abbrev
30897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        return newStart;
30907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
30917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
30927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 6) {
30937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (formatData.shorterWeekdays != null) {
30947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        if((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.shorterWeekdays, null, cal)) > 0) { // try EEEEEE short
30957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            return newStart;
30967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
30977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
30987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
30997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 5) {
31007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (formatData.narrowWeekdays != null) {
31017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        if((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.narrowWeekdays, null, cal)) > 0) { // try EEEEE narrow
31027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            return newStart;
31037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
31047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
31057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
31067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return newStart;
31077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
31087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 25: { // 'c' - STAND_ALONE_DAY_OF_WEEK
31097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if(count == 1 || (number != null && (getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC))) ) {
31107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // i.e. c or lenient and have a number
31117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    cal.set(field, value);
31127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return pos.getIndex();
31137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
31147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // Want to be able to parse at least wide, abbrev, short forms.
31157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                int newStart = 0;
31167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
31177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if ((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.standaloneWeekdays, null, cal)) > 0) { // try cccc wide
31187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        return newStart;
31197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
31207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
31217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
31227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if ((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.standaloneShortWeekdays, null, cal)) > 0) { // try ccc abbrev
31237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        return newStart;
31247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
31257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
31267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 6) {
31277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (formatData.standaloneShorterWeekdays != null) {
31287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        return matchString(text, start, Calendar.DAY_OF_WEEK, formatData.standaloneShorterWeekdays, null, cal); // try cccccc short
31297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
31307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
31317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return newStart;
31327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
3133f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            case 14: { // 'a' - AM_PM
3134f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                // Optionally try both wide/abbrev and narrow forms.
3135f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                // formatData.ampmsNarrow may be null when deserializing DateFormatSymbolsfrom old version,
3136f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                // in which case our only option is wide form
3137f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                int newStart = 0;
3138f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                // try wide/abbrev a-aaaa
3139f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                if(formatData.ampmsNarrow == null || count < 5 || getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH)) {
3140f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                    if ((newStart = matchString(text, start, Calendar.AM_PM, formatData.ampms, null, cal)) > 0) {
3141f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                        return newStart;
3142f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                    }
3143f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                }
3144f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                // try narrow aaaaa
3145f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                if(formatData.ampmsNarrow != null && (count >= 5 || getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH))) {
3146f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                    if ((newStart = matchString(text, start, Calendar.AM_PM, formatData.ampmsNarrow, null, cal)) > 0) {
3147f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                        return newStart;
3148f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                    }
3149f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                }
3150f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                // no matches for given options
3151f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                return ~start;
3152f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            }
31537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 15: // 'h' - HOUR (1..12)
31547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // [We computed 'value' above.]
31557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (value == cal.getLeastMaximum(Calendar.HOUR)+1) {
31567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    value = 0;
31577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
31587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                cal.set(Calendar.HOUR, value);
31597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return pos.getIndex();
31607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 17: // 'z' - ZONE_OFFSET
31617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            {
31627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                Style style = (count < 4) ? Style.SPECIFIC_SHORT : Style.SPECIFIC_LONG;
31637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
31647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (tz != null) {
31657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    cal.setTimeZone(tz);
31667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return pos.getIndex();
31677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
31687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return ~start;
31697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
31707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 23: // 'Z' - TIMEZONE_RFC
31717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            {
31727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                Style style = (count < 4) ? Style.ISO_BASIC_LOCAL_FULL : ((count == 5) ? Style.ISO_EXTENDED_FULL : Style.LOCALIZED_GMT);
31737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
31747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (tz != null) {
31757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    cal.setTimeZone(tz);
31767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return pos.getIndex();
31777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
31787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return ~start;
31797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
31807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 24: // 'v' - TIMEZONE_GENERIC
31817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            {
31827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // Note: 'v' only supports count 1 and 4
31837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                Style style = (count < 4) ? Style.GENERIC_SHORT : Style.GENERIC_LONG;
31847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
31857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (tz != null) {
31867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    cal.setTimeZone(tz);
31877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return pos.getIndex();
31887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
31897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return ~start;
31907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
31917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 29: // 'V' - TIMEZONE_SPECIAL
31927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            {
31937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                Style style = null;
31947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                switch (count) {
31957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                case 1:
31967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    style = Style.ZONE_ID_SHORT;
31977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
31987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                case 2:
31997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    style = Style.ZONE_ID;
32007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
32017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                case 3:
32027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    style = Style.EXEMPLAR_LOCATION;
32037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
32047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                default:
32057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    style = Style.GENERIC_LOCATION;
32067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
32077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
32087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
32097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (tz != null) {
32107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    cal.setTimeZone(tz);
32117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return pos.getIndex();
32127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
32137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return ~start;
32147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
32157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 31: // 'O' - TIMEZONE_LOCALIZED_GMT_OFFSET
32167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            {
32177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                Style style = (count < 4) ? Style.LOCALIZED_GMT_SHORT : Style.LOCALIZED_GMT;
32187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
32197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (tz != null) {
32207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    cal.setTimeZone(tz);
32217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return pos.getIndex();
32227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
32237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return ~start;
32247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
32257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 32: // 'X' - TIMEZONE_ISO
32267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            {
32277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                Style style;
32287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                switch (count) {
32297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                case 1:
32307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    style = Style.ISO_BASIC_SHORT;
32317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
32327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                case 2:
32337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    style = Style.ISO_BASIC_FIXED;
32347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
32357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                case 3:
32367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    style = Style.ISO_EXTENDED_FIXED;
32377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
32387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                case 4:
32397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    style = Style.ISO_BASIC_FULL;
32407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
32417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                default: // count >= 5
32427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    style = Style.ISO_EXTENDED_FULL;
32437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
32447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
32457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
32467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (tz != null) {
32477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    cal.setTimeZone(tz);
32487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return pos.getIndex();
32497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
32507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return ~start;
32517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
32527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 33: // 'x' - TIMEZONE_ISO_LOCAL
32537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            {
32547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                Style style;
32557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                switch (count) {
32567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                case 1:
32577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    style = Style.ISO_BASIC_LOCAL_SHORT;
32587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
32597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                case 2:
32607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    style = Style.ISO_BASIC_LOCAL_FIXED;
32617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
32627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                case 3:
32637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    style = Style.ISO_EXTENDED_LOCAL_FIXED;
32647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
32657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                case 4:
32667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    style = Style.ISO_BASIC_LOCAL_FULL;
32677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
32687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                default: // count >= 5
32697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    style = Style.ISO_EXTENDED_LOCAL_FULL;
32707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
32717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
32727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                TimeZone tz = tzFormat().parse(style, text, pos, tzTimeType);
32737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (tz != null) {
32747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    cal.setTimeZone(tz);
32757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return pos.getIndex();
32767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
32777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return ~start;
32787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
32797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 27: // 'Q' - QUARTER
32807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (count <= 2 || (number != null && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC))) {
32817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // i.e., Q or QQ. or lenient & have number
32827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Don't want to parse the quarter if it is a string
32837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // while pattern uses numeric style: Q or QQ.
32847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // [We computed 'value' above.]
32857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    cal.set(Calendar.MONTH, (value - 1) * 3);
32867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return pos.getIndex();
32877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
32887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // count >= 3 // i.e., QQQ or QQQQ
32897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Want to be able to parse both short and long forms.
32907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Try count == 4 first:
32917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    int newStart = 0;
32927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
32937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        if((newStart = matchQuarterString(text, start, Calendar.MONTH, formatData.quarters, cal)) > 0) {
32947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            return newStart;
32957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
32967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
32977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // count == 4 failed, now try count == 3
32987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
32997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        return matchQuarterString(text, start, Calendar.MONTH,
33007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                           formatData.shortQuarters, cal);
33017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
33027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return newStart;
33037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
33047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
33057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            case 28: // 'q' - STANDALONE QUARTER
33067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (count <= 2 || (number != null && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC))) {
33077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // i.e., q or qq. or lenient & have number
33087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Don't want to parse the quarter if it is a string
33097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // while pattern uses numeric style: q or qq.
33107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // [We computed 'value' above.]
33117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    cal.set(Calendar.MONTH, (value - 1) * 3);
33127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return pos.getIndex();
33137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
33147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // count >= 3 // i.e., qqq or qqqq
33157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Want to be able to parse both short and long forms.
33167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // Try count == 4 first:
33177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    int newStart = 0;
33187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
33197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        if((newStart = matchQuarterString(text, start, Calendar.MONTH, formatData.standaloneQuarters, cal)) > 0) {
33207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            return newStart;
33217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        }
33227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
33237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // count == 4 failed, now try count == 3
33247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
33257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        return matchQuarterString(text, start, Calendar.MONTH,
33267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                           formatData.standaloneShortQuarters, cal);
33277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
33287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return newStart;
33297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
33307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3331bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            case 35: // TIME SEPARATOR (no pattern character currently defined, we should
3332bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                     // not get here but leave support in for future definition.
3333f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            {
3334f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                // Try matching a time separator.
3335f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                ArrayList<String> data = new ArrayList<String>(3);
3336f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                data.add(formatData.getTimeSeparatorString());
3337f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
3338f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                // Add the default, if different from the locale.
3339f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                if (!formatData.getTimeSeparatorString().equals(DateFormatSymbols.DEFAULT_TIME_SEPARATOR)) {
3340f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                    data.add(DateFormatSymbols.DEFAULT_TIME_SEPARATOR);
3341f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                }
3342f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
3343f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                // If lenient, add also the alternate, if different from the locale.
3344bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                if (getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_PARTIAL_LITERAL_MATCH) &&
3345f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                        !formatData.getTimeSeparatorString().equals(DateFormatSymbols.ALTERNATE_TIME_SEPARATOR)) {
3346f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                    data.add(DateFormatSymbols.ALTERNATE_TIME_SEPARATOR);
3347f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                }
3348f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
3349f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                return matchString(text, start, -1 /* => nothing to set */, data.toArray(new String[0]), cal);
3350f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            }
3351f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
33527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            default:
33537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // case 3: // 'd' - DATE
33547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // case 5: // 'H' - HOUR_OF_DAY (0..23)
33557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // case 6: // 'm' - MINUTE
33567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // case 7: // 's' - SECOND
33577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // case 10: // 'D' - DAY_OF_YEAR
33587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // case 11: // 'F' - DAY_OF_WEEK_IN_MONTH
33597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // case 12: // 'w' - WEEK_OF_YEAR
33607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // case 13: // 'W' - WEEK_OF_MONTH
33617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // case 16: // 'K' - HOUR (0..11)
33627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // case 20: // 'u' - EXTENDED_YEAR
33637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // case 21: // 'g' - JULIAN_DAY
33647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // case 22: // 'A' - MILLISECONDS_IN_DAY
3365f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                // case 34: //
33667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
33677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // Handle "generic" fields
33687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (obeyCount) {
33697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if ((start+count) > text.length()) return -start;
33707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    number = parseInt(text, count, pos, allowNegative,currentNumberFormat);
33717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
33727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    number = parseInt(text, pos, allowNegative,currentNumberFormat);
33737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
33747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (number != null) {
3375f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                    if (patternCharIndex != DateFormat.RELATED_YEAR) {
3376f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                        cal.set(field, number.intValue());
3377f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                    } else {
3378f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                        cal.setRelatedYear(number.intValue());
3379f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                    }
33807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return pos.getIndex();
33817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
33827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return ~start;
33837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
33847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
33857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
33867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
33877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * return true if the pattern specified by patternCharIndex is one that allows
33887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * numeric fallback regardless of actual pattern size.
33897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
33907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private boolean allowNumericFallback(int patternCharIndex) {
33917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (patternCharIndex == 26 /*'L' STAND_ALONE_MONTH*/ ||
33927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            patternCharIndex == 19 /*'e' DOW_LOCAL*/ ||
33937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            patternCharIndex == 25 /*'c' STAND_ALONE_DAY_OF_WEEK*/ ||
33947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            patternCharIndex == 30 /*'U' YEAR_NAME_FIELD*/ ||
33957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            patternCharIndex == 27 /* 'Q' - QUARTER*/ ||
33967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            patternCharIndex == 28 /* 'q' - STANDALONE QUARTER*/) {
33977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return true;
33987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
33997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return false;
34007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
34017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
34027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
34037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Parse an integer using numberFormat.  This method is semantically
34047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * const, but actually may modify fNumberFormat.
34057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
34067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private Number parseInt(String text,
34077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            ParsePosition pos,
34087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            boolean allowNegative,
34097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            NumberFormat fmt) {
34107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return parseInt(text, -1, pos, allowNegative, fmt);
34117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
34127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
34137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
34147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Parse an integer using numberFormat up to maxDigits.
34157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
34167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private Number parseInt(String text,
34177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            int maxDigits,
34187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            ParsePosition pos,
34197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            boolean allowNegative,
34207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                            NumberFormat fmt) {
34217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Number number;
34227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int oldPos = pos.getIndex();
34237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (allowNegative) {
34247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            number = fmt.parse(text, pos);
34257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
34267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // Invalidate negative numbers
34277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (fmt instanceof DecimalFormat) {
34287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                String oldPrefix = ((DecimalFormat)fmt).getNegativePrefix();
34297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                ((DecimalFormat)fmt).setNegativePrefix(SUPPRESS_NEGATIVE_PREFIX);
34307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                number = fmt.parse(text, pos);
34317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                ((DecimalFormat)fmt).setNegativePrefix(oldPrefix);
34327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
34337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                boolean dateNumberFormat = (fmt instanceof DateNumberFormat);
34347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (dateNumberFormat) {
34357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    ((DateNumberFormat)fmt).setParsePositiveOnly(true);
34367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
34377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                number = fmt.parse(text, pos);
34387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (dateNumberFormat) {
34397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    ((DateNumberFormat)fmt).setParsePositiveOnly(false);
34407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
34417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
34427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
34437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (maxDigits > 0) {
34447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // adjust the result to fit into
34457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // the maxDigits and move the position back
34467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            int nDigits = pos.getIndex() - oldPos;
34477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (nDigits > maxDigits) {
34487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                double val = number.doubleValue();
34497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                nDigits -= maxDigits;
34507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                while (nDigits > 0) {
34517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    val /= 10;
34527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    nDigits--;
34537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
34547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                pos.setIndex(oldPos + maxDigits);
34557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                number = Integer.valueOf((int)val);
34567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
34577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
34587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return number;
34597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
34607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
34617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
34627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
34637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Translate a pattern, mapping each character in the from string to the
34647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * corresponding character in the to string.
34657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
34667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private String translatePattern(String pat, String from, String to) {
34677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        StringBuilder result = new StringBuilder();
34687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        boolean inQuote = false;
34697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (int i = 0; i < pat.length(); ++i) {
34707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            char c = pat.charAt(i);
34717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (inQuote) {
34727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (c == '\'')
34737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    inQuote = false;
34747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
34757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (c == '\'') {
34767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    inQuote = true;
3477f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                } else if (isSyntaxChar(c)) {
34787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    int ci = from.indexOf(c);
34797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    if (ci != -1) {
34807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                        c = to.charAt(ci);
34817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    }
34827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // do not worry on translatepattern if the character is not listed
34837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    // we do the validity check elsewhere
34847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
34857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
34867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            result.append(c);
34877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
34887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (inQuote) {
34897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new IllegalArgumentException("Unfinished quote in pattern");
34907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
34917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return result.toString();
34927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
34937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
34947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
34957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Return a pattern string describing this date format.
34967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
34977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
34987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public String toPattern() {
34997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return pattern;
35007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
35017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
35027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
35037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Return a localized pattern string describing this date format.
35047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
35057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
35067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public String toLocalizedPattern() {
35077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return translatePattern(pattern,
35087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                DateFormatSymbols.patternChars,
35097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                formatData.localPatternChars);
35107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
35117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
35127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
35137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Apply the given unlocalized pattern string to this date format.
35147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
35157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
35167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void applyPattern(String pat)
35177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
35187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this.pattern = pat;
35197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        setLocale(null, null);
35207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // reset parsed pattern items
35217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        patternItems = null;
35227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
35237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
35247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
35257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Apply the given localized pattern string to this date format.
35267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
35277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
35287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void applyLocalizedPattern(String pat) {
35297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this.pattern = translatePattern(pat,
35307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        formatData.localPatternChars,
35317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        DateFormatSymbols.patternChars);
35327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        setLocale(null, null);
35337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
35347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
35357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
35367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Gets the date/time formatting data.
35377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return a copy of the date-time formatting data associated
35387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * with this date-time formatter.
35397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
35407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
35417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public DateFormatSymbols getDateFormatSymbols()
35427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
35437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return (DateFormatSymbols)formatData.clone();
35447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
35457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
35467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
35477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Allows you to set the date/time formatting data.
35487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param newFormatSymbols the new symbols
35497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
35507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
35517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setDateFormatSymbols(DateFormatSymbols newFormatSymbols)
35527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
35537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        this.formatData = (DateFormatSymbols)newFormatSymbols.clone();
35547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
35557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
35567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
35577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Method for subclasses to access the DateFormatSymbols.
35587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
35597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
35607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    protected DateFormatSymbols getSymbols() {
35617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return formatData;
35627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
35637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
35647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
35657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * {@icu} Gets the time zone formatter which this date/time
35667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * formatter uses to format and parse a time zone.
35677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
35687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return the time zone formatter which this date/time
35697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * formatter uses.
35707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 49
35717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
35727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public TimeZoneFormat getTimeZoneFormat() {
35737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return tzFormat().freeze();
35747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
35757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
35767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
35777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * {@icu} Allows you to set the time zone formatter.
35787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
35797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param tzfmt the new time zone formatter
35807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 49
35817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
35827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setTimeZoneFormat(TimeZoneFormat tzfmt) {
35837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (tzfmt.isFrozen()) {
35847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // If frozen, use it as is.
35857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            tzFormat = tzfmt;
35867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
35877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // If not frozen, clone and freeze.
35887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            tzFormat = tzfmt.cloneAsThawed().freeze();
35897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
35907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
35917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
35927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
35937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Overrides Cloneable
35947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
35957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
35967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public Object clone() {
35977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        SimpleDateFormat other = (SimpleDateFormat) super.clone();
35987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        other.formatData = (DateFormatSymbols) formatData.clone();
3599f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        // We must create a new copy of work buffer used by
3600f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        // the fast numeric field format code.
3601f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        if (this.decimalBuf != null) {
3602f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            other.decimalBuf = new char[DECIMAL_BUF_SIZE];
3603f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        }
36047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return other;
36057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
36067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
36077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
36087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Override hashCode.
36097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Generates the hash code for the SimpleDateFormat object
36107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
36117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
36127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public int hashCode()
36137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
36147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return pattern.hashCode();
36157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // just enough fields for a reasonable distribution
36167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
36177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
36187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
36197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Override equals.
36207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 2.0
36217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
36227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public boolean equals(Object obj)
36237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
36247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (!super.equals(obj)) return false; // super does class check
36257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        SimpleDateFormat that = (SimpleDateFormat) obj;
36267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return (pattern.equals(that.pattern)
36277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                && formatData.equals(that.formatData));
36287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
36297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
36307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
36317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Override writeObject.
36327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * See http://docs.oracle.com/javase/6/docs/api/java/io/ObjectOutputStream.html
36337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
36347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private void writeObject(ObjectOutputStream stream) throws IOException{
36357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (defaultCenturyStart == null) {
36367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // if defaultCenturyStart is not yet initialized,
36377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // calculate and set value before serialization.
36387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            initializeDefaultCenturyStart(defaultCenturyBase);
36397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
36407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        initializeTimeZoneFormat(false);
36417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        stream.defaultWriteObject();
36427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        stream.writeInt(getContext(DisplayContext.Type.CAPITALIZATION).value());
36437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
36447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
36457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
36467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Override readObject.
36477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * See http://docs.oracle.com/javase/6/docs/api/java/io/ObjectInputStream.html
36487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
36497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private void readObject(ObjectInputStream stream)
36507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        throws IOException, ClassNotFoundException {
36517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        stream.defaultReadObject();
36527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int capitalizationSettingValue = (serialVersionOnStream > 1)? stream.readInt(): -1;
36537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        ///CLOVER:OFF
36547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // don't have old serial data to test with
36557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (serialVersionOnStream < 1) {
36567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // didn't have defaultCenturyStart field
36577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            defaultCenturyBase = System.currentTimeMillis();
36587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
36597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        ///CLOVER:ON
36607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        else {
36617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // fill in dependent transient field
36627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            parseAmbiguousDatesAsAfter(defaultCenturyStart);
36637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
36647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        serialVersionOnStream = currentSerialVersion;
36657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        locale = getLocale(ULocale.VALID_LOCALE);
36667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (locale == null) {
36677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // ICU4J 3.6 or older versions did not have UFormat locales
36687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // in the serialized data. This is just for preventing the
36697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // worst case scenario...
36707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            locale = ULocale.getDefault(Category.FORMAT);
36717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
36727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
36737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        initLocalZeroPaddingNumberFormat();
36747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
36757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        setContext(DisplayContext.CAPITALIZATION_NONE);
36767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (capitalizationSettingValue >= 0) {
36777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            for (DisplayContext context: DisplayContext.values()) {
36787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (context.value() == capitalizationSettingValue) {
36797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    setContext(context);
36807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
36817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
36827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
36837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3684bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
3685bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        // if serialized pre-56 update & turned off partial match switch to new enum value
3686bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_PARTIAL_MATCH) == false) {
3687bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            setBooleanAttribute(DateFormat.BooleanAttribute.PARSE_PARTIAL_LITERAL_MATCH, false);
3688bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
36897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
36907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
36917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
36927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Format the object to an attributed string, and return the corresponding iterator
36937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Overrides superclass method.
36947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
36957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param obj The object to format
36967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return <code>AttributedCharacterIterator</code> describing the formatted value.
36977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
36987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @stable ICU 3.8
36997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
37007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
37017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Calendar cal = calendar;
37027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (obj instanceof Calendar) {
37037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            cal = (Calendar)obj;
37047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else if (obj instanceof Date) {
37057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            calendar.setTime((Date)obj);
37067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else if (obj instanceof Number) {
37077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            calendar.setTimeInMillis(((Number)obj).longValue());
37087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
37097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new IllegalArgumentException("Cannot format given Object as a Date");
37107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
37117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        StringBuffer toAppendTo = new StringBuffer();
37127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        FieldPosition pos = new FieldPosition(0);
37137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        List<FieldPosition> attributes = new ArrayList<FieldPosition>();
37147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        format(cal, getContext(DisplayContext.Type.CAPITALIZATION), toAppendTo, pos, attributes);
37157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
37167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        AttributedString as = new AttributedString(toAppendTo.toString());
37177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
37187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // add DateFormat field attributes to the AttributedString
37197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (int i = 0; i < attributes.size(); i++) {
37207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            FieldPosition fp = attributes.get(i);
37217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            Format.Field attribute = fp.getFieldAttribute();
37227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            as.addAttribute(attribute, attribute, fp.getBeginIndex(), fp.getEndIndex());
37237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
37247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // return the CharacterIterator from AttributedString
37257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return as.getIterator();
37267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
37277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
37287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
37297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Get the locale of this simple date formatter.
37307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * It is package accessible. also used in DateIntervalFormat.
37317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
37327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return   locale in this simple date formatter
37337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
37347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    ULocale getLocale()
37357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
37367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return locale;
37377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
37387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
37397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
37407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
37417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
37427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Check whether the 'field' is smaller than all the fields covered in
37437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * pattern, return true if it is.
37447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * The sequence of calendar field,
37457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * from large to small is: ERA, YEAR, MONTH, DATE, AM_PM, HOUR, MINUTE,...
37467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param field    the calendar field need to check against
37477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return         true if the 'field' is smaller than all the fields
37487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                 covered in pattern. false otherwise.
37497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
37507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
37517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    boolean isFieldUnitIgnored(int field) {
37527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return isFieldUnitIgnored(pattern, field);
37537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
37547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
37557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
37567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /*
37577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Check whether the 'field' is smaller than all the fields covered in
37587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * pattern, return true if it is.
37597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * The sequence of calendar field,
37607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * from large to small is: ERA, YEAR, MONTH, DATE, AM_PM, HOUR, MINUTE,...
37617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param pattern  the pattern to check against
37627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param field    the calendar field need to check against
37637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return         true if the 'field' is smaller than all the fields
37647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                 covered in pattern. false otherwise.
37657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
37667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static boolean isFieldUnitIgnored(String pattern, int field) {
37677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int fieldLevel = CALENDAR_FIELD_TO_LEVEL[field];
37687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int level;
37697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        char ch;
37707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        boolean inQuote = false;
37717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        char prevCh = 0;
37727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int count = 0;
37737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
37747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (int i = 0; i < pattern.length(); ++i) {
37757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            ch = pattern.charAt(i);
37767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (ch != prevCh && count > 0) {
3777f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                level = getLevelFromChar(prevCh);
3778f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                if (fieldLevel <= level) {
37797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    return false;
37807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
37817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                count = 0;
37827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
37837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (ch == '\'') {
37847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if ((i+1) < pattern.length() && pattern.charAt(i+1) == '\'') {
37857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    ++i;
37867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
37877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    inQuote = ! inQuote;
37887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
3789f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            } else if (!inQuote && isSyntaxChar(ch)) {
37907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                prevCh = ch;
37917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                ++count;
37927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
37937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
37947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (count > 0) {
37957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // last item
3796f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            level = getLevelFromChar(prevCh);
3797f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            if (fieldLevel <= level) {
37987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return false;
37997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
38007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
38017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return true;
38027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
38037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
38047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
38057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
38067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Format date interval by algorithm.
38077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * It is supposed to be used only by CLDR survey tool.
38087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
38097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param fromCalendar      calendar set to the from date in date interval
38107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                          to be formatted into date interval stirng
38117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param toCalendar        calendar set to the to date in date interval
38127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                          to be formatted into date interval stirng
38137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param appendTo          Output parameter to receive result.
38147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                          Result is appended to existing contents.
38157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param pos               On input: an alignment field, if desired.
38167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                          On output: the offsets of the alignment field.
38177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @exception IllegalArgumentException when there is non-recognized
38187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                                     pattern letter
38197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return                  Reference to 'appendTo' parameter.
38207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @internal
38217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @deprecated This API is ICU internal only.
38227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
38237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Deprecated
38247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public final StringBuffer intervalFormatByAlgorithm(Calendar fromCalendar,
38257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                                        Calendar toCalendar,
38267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                                        StringBuffer appendTo,
38277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                                        FieldPosition pos)
38287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                              throws IllegalArgumentException
38297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    {
38307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // not support different calendar types and time zones
38317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if ( !fromCalendar.isEquivalentTo(toCalendar) ) {
38327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new IllegalArgumentException("can not format on two different calendars");
38337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
38347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
38357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Object[] items = getPatternItems();
38367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int diffBegin = -1;
38377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int diffEnd = -1;
38387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
38397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /* look for different formatting string range */
38407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // look for start of difference
38417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        try {
38427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            for (int i = 0; i < items.length; i++) {
38437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if ( diffCalFieldValue(fromCalendar, toCalendar, items, i) ) {
38447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    diffBegin = i;
38457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
38467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
38477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
38487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
38497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if ( diffBegin == -1 ) {
38507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // no difference, single date format
38517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                return format(fromCalendar, appendTo, pos);
38527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
38537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
38547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            // look for end of difference
38557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            for (int i = items.length-1; i >= diffBegin; i--) {
38567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if ( diffCalFieldValue(fromCalendar, toCalendar, items, i) ) {
38577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    diffEnd = i;
38587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
38597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
38607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
38617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } catch ( IllegalArgumentException e ) {
38627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new IllegalArgumentException(e.toString());
38637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
38647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
38657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // full range is different
38667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if ( diffBegin == 0 && diffEnd == items.length-1 ) {
38677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            format(fromCalendar, appendTo, pos);
38687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            appendTo.append(" \u2013 "); // default separator
38697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            format(toCalendar, appendTo, pos);
38707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return appendTo;
38717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
38727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
38737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
38747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /* search for largest calendar field within the different range */
38757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int highestLevel = 1000;
38767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (int i = diffBegin; i <= diffEnd; i++) {
38777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if ( items[i] instanceof String) {
38787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                continue;
38797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
38807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            PatternItem item = (PatternItem)items[i];
38817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            char ch = item.type;
3882f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            int patternCharIndex = getIndexFromChar(ch);
38837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (patternCharIndex == -1) {
38847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException("Illegal pattern character " +
38857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                                   "'" + ch + "' in \"" +
38867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                                   pattern + '"');
38877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
38887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
38897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if ( patternCharIndex < highestLevel ) {
38907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                highestLevel = patternCharIndex;
38917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
38927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
38937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
38947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        /* re-calculate diff range, including those calendar field which
38957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert           is in lower level than the largest calendar field covered
38967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert           in diff range calculated. */
38977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        try {
38987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            for (int i = 0; i < diffBegin; i++) {
38997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if ( lowerLevel(items, i, highestLevel) ) {
39007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    diffBegin = i;
39017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
39027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
39037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
39047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
39057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
39067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            for (int i = items.length-1; i > diffEnd; i--) {
39077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if ( lowerLevel(items, i, highestLevel) ) {
39087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    diffEnd = i;
39097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    break;
39107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
39117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
39127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } catch ( IllegalArgumentException e ) {
39137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new IllegalArgumentException(e.toString());
39147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
39157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
39167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
39177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // full range is different
39187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if ( diffBegin == 0 && diffEnd == items.length-1 ) {
39197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            format(fromCalendar, appendTo, pos);
39207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            appendTo.append(" \u2013 "); // default separator
39217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            format(toCalendar, appendTo, pos);
39227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return appendTo;
39237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
39247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
39257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
39267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // formatting
39277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Initialize
39287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        pos.setBeginIndex(0);
39297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        pos.setEndIndex(0);
39307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        DisplayContext capSetting = getContext(DisplayContext.Type.CAPITALIZATION);
39317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
39327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // formatting date 1
39337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (int i = 0; i <= diffEnd; i++) {
39347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (items[i] instanceof String) {
39357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                appendTo.append((String)items[i]);
39367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
39377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                PatternItem item = (PatternItem)items[i];
39387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (useFastFormat) {
39397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    subFormat(appendTo, item.type, item.length, appendTo.length(),
39407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                              i, capSetting, pos, fromCalendar);
39417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
39427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    appendTo.append(subFormat(item.type, item.length, appendTo.length(),
39437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                              i, capSetting, pos, fromCalendar));
39447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
39457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
39467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
39477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
39487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        appendTo.append(" \u2013 "); // default separator
39497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
39507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // formatting date 2
39517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (int i = diffBegin; i < items.length; i++) {
39527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (items[i] instanceof String) {
39537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                appendTo.append((String)items[i]);
39547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
39557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                PatternItem item = (PatternItem)items[i];
39567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                if (useFastFormat) {
39577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    subFormat(appendTo, item.type, item.length, appendTo.length(),
39587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                              i, capSetting, pos, toCalendar);
39597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                } else {
39607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    appendTo.append(subFormat(item.type, item.length, appendTo.length(),
39617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                              i, capSetting, pos, toCalendar));
39627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                }
39637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
39647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
39657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return appendTo;
39667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
39677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
39687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
39697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
39707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * check whether the i-th item in 2 calendar is in different value.
39717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
39727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * It is supposed to be used only by CLDR survey tool.
39737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * It is used by intervalFormatByAlgorithm().
39747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
39757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param fromCalendar   one calendar
39767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param toCalendar     the other calendar
39777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param items          pattern items
39787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param i              the i-th item in pattern items
39797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @exception IllegalArgumentException when there is non-recognized
39807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                                     pattern letter
39817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return               true is i-th item in 2 calendar is in different
39827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                       value, false otherwise.
39837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
39847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private boolean diffCalFieldValue(Calendar fromCalendar,
39857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                      Calendar toCalendar,
39867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                      Object[] items,
39877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                      int i) throws IllegalArgumentException {
39887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if ( items[i] instanceof String) {
39897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return false;
39907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
39917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        PatternItem item = (PatternItem)items[i];
39927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        char ch = item.type;
3993f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        int patternCharIndex = getIndexFromChar(ch);
39947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (patternCharIndex == -1) {
39957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new IllegalArgumentException("Illegal pattern character " +
39967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                               "'" + ch + "' in \"" +
39977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                               pattern + '"');
39987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
39997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
40007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        final int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
4001f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        if (field >= 0) {
4002f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            int value = fromCalendar.get(field);
4003f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            int value_2 = toCalendar.get(field);
4004f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            if ( value != value_2 ) {
4005f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                return true;
4006f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            }
40077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
40087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return false;
40097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
40107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
40117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
40127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
40137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * check whether the i-th item's level is lower than the input 'level'
40147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
40157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * It is supposed to be used only by CLDR survey tool.
40167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * It is used by intervalFormatByAlgorithm().
40177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
40187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param items  the pattern items
40197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param i      the i-th item in pattern items
40207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param level  the level with which the i-th pattern item compared to
40217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @exception IllegalArgumentException when there is non-recognized
40227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *                                     pattern letter
40237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return       true if i-th pattern item is lower than 'level',
40247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *               false otherwise
40257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
40267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private boolean lowerLevel(Object[] items, int i, int level)
40277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                    throws IllegalArgumentException {
4028f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        if (items[i] instanceof String) {
40297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return false;
40307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
40317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        PatternItem item = (PatternItem)items[i];
40327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        char ch = item.type;
4033f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        int patternCharIndex = getLevelFromChar(ch);
40347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (patternCharIndex == -1) {
40357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new IllegalArgumentException("Illegal pattern character " +
40367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                               "'" + ch + "' in \"" +
40377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                               pattern + '"');
40387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
40397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4040f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        if (patternCharIndex >= level) {
40417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return true;
40427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
40437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return false;
40447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
40457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
40467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
40477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * allow the user to set the NumberFormat for several fields
40487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * It can be a single field like: "y"(year) or "M"(month)
40497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * It can be several field combined together: "yMd"(year, month and date)
40507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Note:
40517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * 1 symbol field is enough for multiple symbol fields (so "y" will override "yy", "yyy")
40527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * If the field is not numeric, then override has no effect (like "MMM" will use abbreviation, not numerical field)
40537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
40547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param fields the fields to override
40557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param overrideNF the NumbeferFormat used
40567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @exception IllegalArgumentException when the fields contain invalid field
4057bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     * @stable ICU 54
40587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
40597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setNumberFormat(String fields, NumberFormat overrideNF) {
40607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        overrideNF.setGroupingUsed(false);
40617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String nsName = "$" + UUID.randomUUID().toString();
40627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
40637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // initialize mapping if not there
40647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (numberFormatters == null) {
40657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            numberFormatters = new HashMap<String, NumberFormat>();
40667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
40677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (overrideMap == null) {
40687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            overrideMap = new HashMap<Character, String>();
40697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
40707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
40717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // separate string into char and add to maps
40727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for (int i = 0; i < fields.length(); i++) {
40737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            char field = fields.charAt(i);
40747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (DateFormatSymbols.patternChars.indexOf(field) == -1) {
40757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                throw new IllegalArgumentException("Illegal field character " + "'" + field + "' in setNumberFormat.");
40767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
40777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            overrideMap.put(field, nsName);
40787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            numberFormatters.put(nsName, overrideNF);
40797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
40807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
40817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Since one or more of the override number formatters might be complex,
40827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // we can't rely on the fast numfmt where we have a partial field override.
40837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        useLocalZeroPaddingNumberFormat = false;
40847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
40857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
40867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
40877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * give the NumberFormat used for the field like 'y'(year) and 'M'(year)
40887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
40897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @param field the field the user wants
40907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * @return override NumberFormat used for the field
4091bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     * @stable ICU 54
40927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
40937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public NumberFormat getNumberFormat(char field) {
40947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Character ovrField;
40957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        ovrField = Character.valueOf(field);
40967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if (overrideMap != null && overrideMap.containsKey(ovrField)) {
40977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            String nsName = overrideMap.get(ovrField).toString();
40987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            NumberFormat nf = numberFormatters.get(nsName);
40997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return nf;
41007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
41017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return numberFormat;
41027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
41037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
41047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
41057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private void initNumberFormatters(ULocale loc) {
41067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
41077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert       numberFormatters = new HashMap<String, NumberFormat>();
41087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert       overrideMap = new HashMap<Character, String>();
41097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert       processOverrideString(loc,override);
41107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
41117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
41127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
41137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private void processOverrideString(ULocale loc, String str) {
41147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
41157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if ( str == null || str.length() == 0 )
41167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            return;
41177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
41187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int start = 0;
41197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int end;
41207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        String nsName;
41217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        Character ovrField;
41227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        boolean moreToProcess = true;
41237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        boolean fullOverride;
41247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
41257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        while (moreToProcess) {
41267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            int delimiterPosition = str.indexOf(";",start);
41277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (delimiterPosition == -1) {
41287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                moreToProcess = false;
41297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                end = str.length();
41307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
41317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                end = delimiterPosition;
41327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
41337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
41347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            String currentString = str.substring(start,end);
41357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            int equalSignPosition = currentString.indexOf("=");
41367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (equalSignPosition == -1) { // Simple override string such as "hebrew"
41377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert               nsName = currentString;
41387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert               fullOverride = true;
41397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else { // Field specific override string such as "y=hebrew"
41407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert               nsName = currentString.substring(equalSignPosition+1);
41417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert               ovrField = Character.valueOf(currentString.charAt(0));
41427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert               overrideMap.put(ovrField,nsName);
41437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert               fullOverride = false;
41447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
41457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
41467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            ULocale ovrLoc = new ULocale(loc.getBaseName()+"@numbers="+nsName);
41477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            NumberFormat nf = NumberFormat.createInstance(ovrLoc,NumberFormat.NUMBERSTYLE);
41487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            nf.setGroupingUsed(false);
41497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
41507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (fullOverride) {
41517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                setNumberFormat(nf);
41527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            } else {
41537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // Since one or more of the override number formatters might be complex,
41547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                // we can't rely on the fast numfmt where we have a partial field override.
41557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                useLocalZeroPaddingNumberFormat = false;
41567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
41577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
41587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            if (!fullOverride && !numberFormatters.containsKey(nsName)) {
41597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                  numberFormatters.put(nsName,nf);
41607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            }
41617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
41627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            start = delimiterPosition + 1;
41637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
41647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
41657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert}
4166