151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/*
22c87ad3a45cecf9e344487cad1abfdebe79f2c7cNarayan Kamath * Copyright (C) 2014 The Android Open Source Project
351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is free software; you can redistribute it and/or modify it
751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * under the terms of the GNU General Public License version 2 only, as
851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * published by the Free Software Foundation.  Oracle designates this
951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * particular file as subject to the "Classpath" exception as provided
1051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by Oracle in the LICENSE file that accompanied this code.
1151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is distributed in the hope that it will be useful, but WITHOUT
1351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * version 2 for more details (a copy is included in the LICENSE file that
1651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accompanied this code).
1751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * You should have received a copy of the GNU General Public License version
1951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2 along with this work; if not, write to the Free Software Foundation,
2051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
2251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * or visit www.oracle.com if you need additional information or have any
2451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * questions.
2551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
2651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/*
2851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
2951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
3051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
3151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *   The original version of this source code and documentation is copyrighted
3251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
3351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * materials are provided under terms of a License Agreement between Taligent
3451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * and Sun. This technology is protected by multiple US and International
3551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * patents. This notice and attribution to Taligent may not be removed.
3651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *   Taligent is a registered trademark of Taligent, Inc.
3751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
3851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
3951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
4051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipackage java.text;
4151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
424947038a7acb466855746df19d41ef26be507aa4Joachim Sauerimport android.icu.text.TimeZoneFormat;
434947038a7acb466855746df19d41ef26be507aa4Joachim Sauerimport android.icu.text.TimeZoneNames;
444947038a7acb466855746df19d41ef26be507aa4Joachim Sauerimport android.icu.util.ULocale;
454947038a7acb466855746df19d41ef26be507aa4Joachim Sauer
4651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.io.IOException;
4751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.io.InvalidObjectException;
4851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.io.ObjectInputStream;
494947038a7acb466855746df19d41ef26be507aa4Joachim Sauerimport java.util.Arrays;
5051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Calendar;
514947038a7acb466855746df19d41ef26be507aa4Joachim Sauerimport java.util.Collection;
524947038a7acb466855746df19d41ef26be507aa4Joachim Sauerimport java.util.Collections;
5351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Date;
544947038a7acb466855746df19d41ef26be507aa4Joachim Sauerimport java.util.EnumSet;
5551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.GregorianCalendar;
564947038a7acb466855746df19d41ef26be507aa4Joachim Sauerimport java.util.HashSet;
5751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Locale;
5851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.Map;
594947038a7acb466855746df19d41ef26be507aa4Joachim Sauerimport java.util.Set;
6051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.SimpleTimeZone;
6151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.TimeZone;
6251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.concurrent.ConcurrentHashMap;
6351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.concurrent.ConcurrentMap;
649c853c5b9ebbb0ef60a013ae10ee411d70dfa832Piotr Jastrzebskiimport libcore.icu.LocaleData;
65d8bef3c23bf1851242cc2dc189edaa544eeabe58Joachim Sauer
6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport sun.util.calendar.CalendarUtils;
6751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
6851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport static java.text.DateFormatSymbols.*;
6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
70a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak// Android-changed: Added supported API level, removed unnecessary <br>
71d48197ec78f54c6adb3fec78c3bcc384b7ce2e40Przemyslaw Szczepaniak// Android-changed: Clarified info about X symbol time zone parsing
7251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/**
7351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>SimpleDateFormat</code> is a concrete class for formatting and
7451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * parsing dates in a locale-sensitive manner. It allows for formatting
756e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin * (date &rarr; text), parsing (text &rarr; date), and normalization.
7651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
7751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p>
7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>SimpleDateFormat</code> allows you to start by choosing
7951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * any user-defined patterns for date-time formatting. However, you
8051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * are encouraged to create a date-time formatter with either
8151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>getTimeInstance</code>, <code>getDateInstance</code>, or
8251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>getDateTimeInstance</code> in <code>DateFormat</code>. Each
8351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * of these class methods can return a date/time formatter initialized
8451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * with a default format pattern. You may modify the format pattern
8551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * using the <code>applyPattern</code> methods as desired.
8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * For more information on using these methods, see
8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * {@link DateFormat}.
8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
896e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin * <h3>Date and Time Patterns</h3>
9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p>
9151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Date and time formats are specified by <em>date and time pattern</em>
9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * strings.
9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Within date and time pattern strings, unquoted letters from
9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>'A'</code> to <code>'Z'</code> and from <code>'a'</code> to
9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>'z'</code> are interpreted as pattern letters representing the
9651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * components of a date or time string.
9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Text can be quoted using single quotes (<code>'</code>) to avoid
9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * interpretation.
9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>"''"</code> represents a single quote.
10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * All other characters are not interpreted; they're simply copied into the
10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * output string during formatting or matched against the input string
10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * during parsing.
10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p>
10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * The following pattern letters are defined (all other characters from
10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>'A'</code> to <code>'Z'</code> and from <code>'a'</code> to
10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>'z'</code> are reserved):
10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <blockquote>
10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <table border=0 cellspacing=3 cellpadding=0 summary="Chart shows pattern letters, date/time component, presentation, and examples.">
1096e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr style="background-color: rgb(204, 204, 255);">
11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <th align=left>Letter
11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <th align=left>Date or Time Component
11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <th align=left>Presentation
11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <th align=left>Examples
114a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <th align=left>Supported (API Levels)
11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <tr>
11651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>G</code>
11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Era designator
11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#text">Text</a>
11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>AD</code>
120a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
1216e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr style="background-color: rgb(238, 238, 255);">
12251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>y</code>
12351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Year
12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#year">Year</a>
12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>1996</code>; <code>96</code>
126a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <tr>
12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>Y</code>
12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Week year
13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#year">Year</a>
13151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>2009</code>; <code>09</code>
1324772860a6a2e4b4a64747c82a51a968ec08f7e13Joachim Sauer *         <td>24+</td>
1336e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr style="background-color: rgb(238, 238, 255);">
13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>M</code>
1356e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *         <td>Month in year (context sensitive)
13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#month">Month</a>
13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>July</code>; <code>Jul</code>; <code>07</code>
138a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
13951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <tr>
14051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>w</code>
14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Week in year
14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#number">Number</a>
14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>27</code>
144a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
1456e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr>
14651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>W</code>
14751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Week in month
14851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#number">Number</a>
14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>2</code>
150a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
1516e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr style="background-color: rgb(238, 238, 255);">
15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>D</code>
15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Day in year
15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#number">Number</a>
15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>189</code>
156a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
1576e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr>
15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>d</code>
15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Day in month
16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#number">Number</a>
16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>10</code>
162a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
1636e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr style="background-color: rgb(238, 238, 255);">
16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>F</code>
16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Day of week in month
16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#number">Number</a>
16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>2</code>
168a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
1696e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr>
17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>E</code>
17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Day name in week
17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#text">Text</a>
17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>Tuesday</code>; <code>Tue</code>
174a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
1756e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr style="background-color: rgb(238, 238, 255);">
17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>u</code>
17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Day number of week (1 = Monday, ..., 7 = Sunday)
17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#number">Number</a>
17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>1</code>
180a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>24+</td>
1816e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr>
18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>a</code>
18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Am/pm marker
18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#text">Text</a>
18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>PM</code>
186a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
1876e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr style="background-color: rgb(238, 238, 255);">
18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>H</code>
18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Hour in day (0-23)
19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#number">Number</a>
19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>0</code>
192a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
1936e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr>
19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>k</code>
19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Hour in day (1-24)
19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#number">Number</a>
19751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>24</code>
198a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
1996e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr style="background-color: rgb(238, 238, 255);">
20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>K</code>
20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Hour in am/pm (0-11)
20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#number">Number</a>
20351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>0</code>
204a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
2056e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr>
20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>h</code>
20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Hour in am/pm (1-12)
20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#number">Number</a>
20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>12</code>
210a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
2116e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr style="background-color: rgb(238, 238, 255);">
21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>m</code>
21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Minute in hour
21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#number">Number</a>
21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>30</code>
216a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
2176e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr>
21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>s</code>
21951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Second in minute
22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#number">Number</a>
22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>55</code>
222a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
2236e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr style="background-color: rgb(238, 238, 255);">
22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>S</code>
22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Millisecond
22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#number">Number</a>
22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>978</code>
228a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
2296e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr>
23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>z</code>
23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Time zone
23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#timezone">General time zone</a>
23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>Pacific Standard Time</code>; <code>PST</code>; <code>GMT-08:00</code>
234a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
2356e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr style="background-color: rgb(238, 238, 255);">
23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>Z</code>
23751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Time zone
23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#rfc822timezone">RFC 822 time zone</a>
23951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>-0800</code>
240a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *         <td>1+</td>
2416e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr>
24251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>X</code>
24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td>Time zone
24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><a href="#iso8601timezone">ISO 8601 time zone</a>
24551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>-08</code>; <code>-0800</code>;  <code>-08:00</code>
2464772860a6a2e4b4a64747c82a51a968ec08f7e13Joachim Sauer *         <td>24+</td>
24751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * </table>
24851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * </blockquote>
24951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Pattern letters are usually repeated, as their number determines the
25051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * exact presentation:
25151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <ul>
25251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <li><strong><a name="text">Text:</a></strong>
25351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     For formatting, if the number of pattern letters is 4 or more,
25451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     the full form is used; otherwise a short or abbreviated form
25551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     is used if available.
25651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     For parsing, both forms are accepted, independent of the number
257a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *     of pattern letters.</li>
25851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <li><strong><a name="number">Number:</a></strong>
25951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     For formatting, the number of pattern letters is the minimum
26051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     number of digits, and shorter numbers are zero-padded to this amount.
26151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     For parsing, the number of pattern letters is ignored unless
262a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *     it's needed to separate two adjacent fields.</li>
26351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <li><strong><a name="year">Year:</a></strong>
26451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     If the formatter's {@link #getCalendar() Calendar} is the Gregorian
265a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *     calendar, the following rules are applied.
26651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <ul>
26751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <li>For formatting, if the number of pattern letters is 2, the year
26851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         is truncated to 2 digits; otherwise it is interpreted as a
26951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <a href="#number">number</a>.
27051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <li>For parsing, if the number of pattern letters is more than 2,
27151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         the year is interpreted literally, regardless of the number of
27251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         digits. So using the pattern "MM/dd/yyyy", "01/11/12" parses to
27351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         Jan 11, 12 A.D.
27451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <li>For parsing with the abbreviated year pattern ("y" or "yy"),
27551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <code>SimpleDateFormat</code> must interpret the abbreviated year
27651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         relative to some century.  It does this by adjusting dates to be
27751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         within 80 years before and 20 years after the time the <code>SimpleDateFormat</code>
27851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         instance is created. For example, using a pattern of "MM/dd/yy" and a
27951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <code>SimpleDateFormat</code> instance created on Jan 1, 1997,  the string
28051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         "01/11/12" would be interpreted as Jan 11, 2012 while the string "05/04/64"
28151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         would be interpreted as May 4, 1964.
28251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         During parsing, only strings consisting of exactly two digits, as defined by
28351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         {@link Character#isDigit(char)}, will be parsed into the default century.
28451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         Any other numeric string, such as a one digit string, a three or more digit
28551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         string, or a two digit string that isn't all digits (for example, "-1"), is
28651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         interpreted literally.  So "01/02/3" or "01/02/003" are parsed, using the
28751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         same pattern, as Jan 2, 3 AD.  Likewise, "01/02/-3" is parsed as Jan 2, 4 BC.
28851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     </ul>
28951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     Otherwise, calendar system specific forms are applied.
29051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     For both formatting and parsing, if the number of pattern
29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     letters is 4 or more, a calendar specific {@linkplain
29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     Calendar#LONG long form} is used. Otherwise, a calendar
29351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     specific {@linkplain Calendar#SHORT short or abbreviated form}
294a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *     is used.
29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <br>
29651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     If week year {@code 'Y'} is specified and the {@linkplain
29751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     #getCalendar() calendar} doesn't support any <a
29851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     href="../util/GregorianCalendar.html#week_year"> week
29951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     years</a>, the calendar year ({@code 'y'}) is used instead. The
30051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     support of week years can be tested with a call to {@link
30151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     DateFormat#getCalendar() getCalendar()}.{@link
30251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     java.util.Calendar#isWeekDateSupported()
303a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *     isWeekDateSupported()}.</li>
30451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <li><strong><a name="month">Month:</a></strong>
30551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     If the number of pattern letters is 3 or more, the month is
30651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     interpreted as <a href="#text">text</a>; otherwise,
307a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *     it is interpreted as a <a href="#number">number</a>.</li>
30851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <li><strong><a name="timezone">General time zone:</a></strong>
30951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     Time zones are interpreted as <a href="#text">text</a> if they have
31051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     names. For time zones representing a GMT offset value, the
31151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     following syntax is used:
31251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <pre>
31351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <a name="GMTOffsetTimeZone"><i>GMTOffsetTimeZone:</i></a>
31451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *             <code>GMT</code> <i>Sign</i> <i>Hours</i> <code>:</code> <i>Minutes</i>
31551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <i>Sign:</i> one of
31651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *             <code>+ -</code>
31751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <i>Hours:</i>
31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *             <i>Digit</i>
31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *             <i>Digit</i> <i>Digit</i>
32051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <i>Minutes:</i>
32151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *             <i>Digit</i> <i>Digit</i>
32251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <i>Digit:</i> one of
32351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *             <code>0 1 2 3 4 5 6 7 8 9</code></pre>
32451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <i>Hours</i> must be between 0 and 23, and <i>Minutes</i> must be between
32551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     00 and 59. The format is locale independent and digits must be taken
32651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     from the Basic Latin block of the Unicode standard.
32751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <p>For parsing, <a href="#rfc822timezone">RFC 822 time zones</a> are also
328a17c83ea5f83606615aed6a86cbb8a8ad8444723Przemyslaw Szczepaniak *     accepted.</li>
32951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <li><strong><a name="rfc822timezone">RFC 822 time zone:</a></strong>
33051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     For formatting, the RFC 822 4-digit time zone format is used:
33151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
33251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <pre>
33351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <i>RFC822TimeZone:</i>
33451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *             <i>Sign</i> <i>TwoDigitHours</i> <i>Minutes</i>
33551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <i>TwoDigitHours:</i>
33651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *             <i>Digit Digit</i></pre>
33751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <i>TwoDigitHours</i> must be between 00 and 23. Other definitions
33851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     are as for <a href="#timezone">general time zones</a>.
33951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
34051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <p>For parsing, <a href="#timezone">general time zones</a> are also
34151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     accepted.
34251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <li><strong><a name="iso8601timezone">ISO 8601 Time zone:</a></strong>
34351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     The number of pattern letters designates the format for both formatting
34451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     and parsing as follows:
34551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <pre>
34651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <i>ISO8601TimeZone:</i>
34751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *             <i>OneLetterISO8601TimeZone</i>
34851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *             <i>TwoLetterISO8601TimeZone</i>
34951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *             <i>ThreeLetterISO8601TimeZone</i>
35051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <i>OneLetterISO8601TimeZone:</i>
35151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *             <i>Sign</i> <i>TwoDigitHours</i>
35251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *             {@code Z}
35351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <i>TwoLetterISO8601TimeZone:</i>
35451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *             <i>Sign</i> <i>TwoDigitHours</i> <i>Minutes</i>
35551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *             {@code Z}
35651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <i>ThreeLetterISO8601TimeZone:</i>
35751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *             <i>Sign</i> <i>TwoDigitHours</i> {@code :} <i>Minutes</i>
35851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *             {@code Z}</pre>
35951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     Other definitions are as for <a href="#timezone">general time zones</a> or
36051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <a href="#rfc822timezone">RFC 822 time zones</a>.
36151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
36251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <p>For formatting, if the offset value from GMT is 0, {@code "Z"} is
36351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     produced. If the number of pattern letters is 1, any fraction of an hour
36451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     is ignored. For example, if the pattern is {@code "X"} and the time zone is
36551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     {@code "GMT+05:30"}, {@code "+05"} is produced.
36651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
367d48197ec78f54c6adb3fec78c3bcc384b7ce2e40Przemyslaw Szczepaniak *     <p>For parsing, the letter {@code "Z"} is parsed as the UTC time zone designator (therefore
368d48197ec78f54c6adb3fec78c3bcc384b7ce2e40Przemyslaw Szczepaniak *     {@code "09:30Z"} is parsed as {@code "09:30 UTC"}.
36951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <a href="#timezone">General time zones</a> are <em>not</em> accepted.
370d48197ec78f54c6adb3fec78c3bcc384b7ce2e40Przemyslaw Szczepaniak *     <p>If the number of {@code "X"} pattern letters is 4 or more (e.g. {@code XXXX}), {@link
37151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     IllegalArgumentException} is thrown when constructing a {@code
37251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     SimpleDateFormat} or {@linkplain #applyPattern(String) applying a
37351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     pattern}.
37451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * </ul>
37551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>SimpleDateFormat</code> also supports <em>localized date and time
37651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * pattern</em> strings. In these strings, the pattern letters described above
37751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * may be replaced with other, locale dependent, pattern letters.
37851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <code>SimpleDateFormat</code> does not deal with the localization of text
37951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * other than the pattern letters; that's up to the client of the class.
38051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
38151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <h4>Examples</h4>
38251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
38351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * The following examples show how date and time patterns are interpreted in
38451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * the U.S. locale. The given date and time are 2001-07-04 12:08:56 local time
38551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * in the U.S. Pacific Time time zone.
38651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <blockquote>
38751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <table border=0 cellspacing=3 cellpadding=0 summary="Examples of date and time patterns interpreted in the U.S. locale">
3886e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr style="background-color: rgb(204, 204, 255);">
38951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <th align=left>Date and Time Pattern
39051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <th align=left>Result
39151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <tr>
39251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>"yyyy.MM.dd G 'at' HH:mm:ss z"</code>
39351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>2001.07.04 AD at 12:08:56 PDT</code>
3946e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr style="background-color: rgb(238, 238, 255);">
39551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>"EEE, MMM d, ''yy"</code>
39651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>Wed, Jul 4, '01</code>
39751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <tr>
39851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>"h:mm a"</code>
39951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>12:08 PM</code>
4006e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr style="background-color: rgb(238, 238, 255);">
40151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>"hh 'o''clock' a, zzzz"</code>
40251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>12 o'clock PM, Pacific Daylight Time</code>
40351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <tr>
40451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>"K:mm a, z"</code>
40551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>0:08 PM, PDT</code>
4066e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr style="background-color: rgb(238, 238, 255);">
40751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>"yyyyy.MMMMM.dd GGG hh:mm aaa"</code>
40851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>02001.July.04 AD 12:08 PM</code>
40951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <tr>
41051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>"EEE, d MMM yyyy HH:mm:ss Z"</code>
41151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>Wed, 4 Jul 2001 12:08:56 -0700</code>
4126e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr style="background-color: rgb(238, 238, 255);">
41351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>"yyMMddHHmmssZ"</code>
41451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>010704120856-0700</code>
41551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <tr>
41651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>"yyyy-MM-dd'T'HH:mm:ss.SSSZ"</code>
41751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>2001-07-04T12:08:56.235-0700</code>
4186e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin *     <tr style="background-color: rgb(238, 238, 255);">
41951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>"yyyy-MM-dd'T'HH:mm:ss.SSSXXX"</code>
42051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>2001-07-04T12:08:56.235-07:00</code>
42151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *     <tr>
42251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>"YYYY-'W'ww-u"</code>
42351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *         <td><code>2001-W27-3</code>
42451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * </table>
42551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * </blockquote>
42651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
42751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <h4><a name="synchronization">Synchronization</a></h4>
42851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
42951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * <p>
43051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Date formats are not synchronized.
43151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * It is recommended to create separate format instances for each thread.
43251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * If multiple threads access a format concurrently, it must be synchronized
43351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * externally.
43451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
4356e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin * @see          <a href="https://docs.oracle.com/javase/tutorial/i18n/format/simpleDateFormat.html">Java Tutorial</a>
43651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @see          java.util.Calendar
43751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @see          java.util.TimeZone
43851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @see          DateFormat
43951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @see          DateFormatSymbols
44051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * @author       Mark Davis, Chen-Lieh Huang, Alan Liu
44151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
44251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipublic class SimpleDateFormat extends DateFormat {
44351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
44451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // the official serial version ID which says cryptically
44551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // which version we're compatible with
44651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    static final long serialVersionUID = 4774881970558875024L;
44751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
44851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // the internal serial version which says which version was written
44951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // - 0 (default) for version up to JDK 1.1.3
45051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // - 1 for version from JDK 1.1.4, which includes a new field
45151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    static final int currentSerialVersion = 1;
45251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
45351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
45451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * The version of the serialized data on the stream.  Possible values:
45551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <ul>
45651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <li><b>0</b> or not present on stream: JDK 1.1.3.  This version
45751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * has no <code>defaultCenturyStart</code> on stream.
45851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <li><b>1</b> JDK 1.1.4 or later.  This version adds
45951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>defaultCenturyStart</code>.
46051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * </ul>
46151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * When streaming out this class, the most recent format
46251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * and the highest allowable <code>serialVersionOnStream</code>
46351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * is written.
46451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @serial
46551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @since JDK1.1.4
46651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
46751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private int serialVersionOnStream = currentSerialVersion;
46851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
46951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
47051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * The pattern string of this formatter.  This is always a non-localized
47151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * pattern.  May not be null.  See class documentation for details.
47251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @serial
47351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
47451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private String pattern;
47551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
47651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
47751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Saved numberFormat and pattern.
47851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @see SimpleDateFormat#checkNegativeNumberExpression
47951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
48051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    transient private NumberFormat originalNumberFormat;
48151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    transient private String originalNumberPattern;
48251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
48351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
48451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * The minus sign to be used with format and parse.
48551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
48651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    transient private char minusSign = '-';
48751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
48851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
48951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * True when a negative sign follows a number.
49051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * (True as default in Arabic.)
49151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
49251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    transient private boolean hasFollowingMinusSign = false;
49351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
49451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
49551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * The compiled pattern.
49651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
49751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    transient private char[] compiledPattern;
49851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
49951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
50051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Tags for the compiled pattern.
50151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
50251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private final static int TAG_QUOTE_ASCII_CHAR       = 100;
50351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private final static int TAG_QUOTE_CHARS            = 101;
50451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
50551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
50651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Locale dependent digit zero.
50751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @see #zeroPaddingNumber
50851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @see java.text.DecimalFormatSymbols#getZeroDigit
50951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
51051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    transient private char zeroDigit;
51151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
51251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
51351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * The symbols used by this formatter for week names, month names,
51451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * etc.  May not be null.
51551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @serial
51651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @see java.text.DateFormatSymbols
51751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
51851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private DateFormatSymbols formatData;
51951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
52051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
52151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * We map dates with two-digit years into the century starting at
52251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>defaultCenturyStart</code>, which may be any date.  May
52351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * not be null.
52451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @serial
52551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @since JDK1.1.4
52651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
52751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private Date defaultCenturyStart;
52851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
52951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    transient private int defaultCenturyStartYear;
53051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
53151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int MILLIS_PER_MINUTE = 60 * 1000;
53251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
53351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // For time zones that have no names, use strings GMT+minutes and
53451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // GMT-minutes. For instance, in France the time zone is GMT+60.
53551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final String GMT = "GMT";
53651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
53751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
53851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Cache NumberFormat instances with Locale key.
53951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
54051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final ConcurrentMap<Locale, NumberFormat> cachedNumberFormatData
541af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin        = new ConcurrentHashMap<>(3);
54251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
54351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
54451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * The Locale used to instantiate this
54551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>SimpleDateFormat</code>. The value may be null if this object
54651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * has been created by an older <code>SimpleDateFormat</code> and
54751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * deserialized.
54851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
54951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @serial
55051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @since 1.6
55151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
55251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private Locale locale;
55351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
55451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
55551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Indicates whether this <code>SimpleDateFormat</code> should use
55651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * the DateFormatSymbols. If true, the format and parse methods
55751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * use the DateFormatSymbols values. If false, the format and
55851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * parse methods call Calendar.getDisplayName or
55951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Calendar.getDisplayNames.
56051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
56151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    transient boolean useDateFormatSymbols;
56251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
563d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer    // Android-added: ICU TimeZoneNames field.
56451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
5654947038a7acb466855746df19d41ef26be507aa4Joachim Sauer     * ICU TimeZoneNames used to format and parse time zone names.
5664947038a7acb466855746df19d41ef26be507aa4Joachim Sauer     */
5674947038a7acb466855746df19d41ef26be507aa4Joachim Sauer    private transient TimeZoneNames timeZoneNames;
5684947038a7acb466855746df19d41ef26be507aa4Joachim Sauer
5694947038a7acb466855746df19d41ef26be507aa4Joachim Sauer    /**
57051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Constructs a <code>SimpleDateFormat</code> using the default pattern and
5716e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin     * date format symbols for the default
5726e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin     * {@link java.util.Locale.Category#FORMAT FORMAT} locale.
57351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <b>Note:</b> This constructor may not support all locales.
57451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * For full coverage, use the factory methods in the {@link DateFormat}
57551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * class.
57651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
57751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public SimpleDateFormat() {
57859f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang        // Android-changed: Android has no LocaleProviderAdapter. Use ICU locale data.
57959f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang        // this("", Locale.getDefault(Locale.Category.FORMAT));
58059f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang        // applyPatternImpl(LocaleProviderAdapter.getResourceBundleBased().getLocaleResources(locale)
58159f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang        //                  .getDateTimePattern(SHORT, SHORT, calendar));
58251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this(SHORT, SHORT, Locale.getDefault(Locale.Category.FORMAT));
58351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
58451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
58559f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang    // BEGIN Android-added: Ctor used by DateFormat to remove use of LocaleProviderAdapter.
58659f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang    /**
58759f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang     * Constructs a <code>SimpleDateFormat</code> using the given date and time formatting styles.
58859f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang     * @param timeStyle the given date formatting style.
58959f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang     * @param dateStyle the given time formatting style.
59059f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang     * @param locale the locale whose pattern and date format symbols should be used
59159f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang     */
59259f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang    SimpleDateFormat(int timeStyle, int dateStyle, Locale locale) {
59359f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang        this(getDateTimeFormat(timeStyle, dateStyle, locale), locale);
59459f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang    }
59559f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang
59659f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang    private static String getDateTimeFormat(int timeStyle, int dateStyle, Locale locale) {
59759f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang        LocaleData localeData = LocaleData.get(locale);
59859f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang        if ((timeStyle >= 0) && (dateStyle >= 0)) {
59959f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang            Object[] dateTimeArgs = {
60059f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang                localeData.getDateFormat(dateStyle),
60159f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang                localeData.getTimeFormat(timeStyle),
60259f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang            };
60359f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang            return MessageFormat.format("{0} {1}", dateTimeArgs);
60459f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang        } else if (timeStyle >= 0) {
60559f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang            return localeData.getTimeFormat(timeStyle);
60659f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang        } else if (dateStyle >= 0) {
60759f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang            return localeData.getDateFormat(dateStyle);
60859f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang        } else {
60959f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang            throw new IllegalArgumentException("No date or time style specified");
61059f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang        }
61159f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang    }
61259f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang    // END Android-added: Ctor used by DateFormat to remove use of LocaleProviderAdapter.
61359f1a7d46654a2893d38532d2cfb33c1e6af1dd4Victor Chang
61451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
61551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Constructs a <code>SimpleDateFormat</code> using the given pattern and
6166e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin     * the default date format symbols for the default
6176e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin     * {@link java.util.Locale.Category#FORMAT FORMAT} locale.
61851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <b>Note:</b> This constructor may not support all locales.
61951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * For full coverage, use the factory methods in the {@link DateFormat}
62051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * class.
6216e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin     * <p>This is equivalent to calling
6226e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin     * {@link #SimpleDateFormat(String, Locale)
6236e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin     *     SimpleDateFormat(pattern, Locale.getDefault(Locale.Category.FORMAT))}.
62451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
6256e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin     * @see java.util.Locale#getDefault(java.util.Locale.Category)
6266e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin     * @see java.util.Locale.Category#FORMAT
62751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param pattern the pattern describing the date and time format
62851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception NullPointerException if the given pattern is null
62951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception IllegalArgumentException if the given pattern is invalid
63051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
63151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public SimpleDateFormat(String pattern)
63251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
63351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this(pattern, Locale.getDefault(Locale.Category.FORMAT));
63451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
63551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
63651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
63751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Constructs a <code>SimpleDateFormat</code> using the given pattern and
63851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * the default date format symbols for the given locale.
63951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <b>Note:</b> This constructor may not support all locales.
64051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * For full coverage, use the factory methods in the {@link DateFormat}
64151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * class.
64251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
64351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param pattern the pattern describing the date and time format
64451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param locale the locale whose date format symbols should be used
64551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception NullPointerException if the given pattern or locale is null
64651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception IllegalArgumentException if the given pattern is invalid
64751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
64851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public SimpleDateFormat(String pattern, Locale locale)
64951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
65051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (pattern == null || locale == null) {
65151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new NullPointerException();
65251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
65351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
65451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        initializeCalendar(locale);
65551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.pattern = pattern;
65651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.formatData = DateFormatSymbols.getInstanceRef(locale);
65751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.locale = locale;
65851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        initialize(locale);
65951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
66051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
66151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
66251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Constructs a <code>SimpleDateFormat</code> using the given pattern and
66351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * date format symbols.
66451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
66551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param pattern the pattern describing the date and time format
66651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param formatSymbols the date format symbols to be used for formatting
66751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception NullPointerException if the given pattern or formatSymbols is null
66851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception IllegalArgumentException if the given pattern is invalid
66951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
67051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public SimpleDateFormat(String pattern, DateFormatSymbols formatSymbols)
67151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
67251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (pattern == null || formatSymbols == null) {
67351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new NullPointerException();
67451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
67551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
67651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.pattern = pattern;
67751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.formatData = (DateFormatSymbols) formatSymbols.clone();
67851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.locale = Locale.getDefault(Locale.Category.FORMAT);
67951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        initializeCalendar(this.locale);
68051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        initialize(this.locale);
68151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        useDateFormatSymbols = true;
68251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
68351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
68451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* Initialize compiledPattern and numberFormat fields */
68551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void initialize(Locale loc) {
68651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // Verify and compile the given pattern.
68751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        compiledPattern = compile(pattern);
68851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
68951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        /* try the cache first */
69051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        numberFormat = cachedNumberFormatData.get(loc);
69151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (numberFormat == null) { /* cache miss */
69251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            numberFormat = NumberFormat.getIntegerInstance(loc);
69351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            numberFormat.setGroupingUsed(false);
69451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
69551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            /* update cache */
69651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            cachedNumberFormatData.putIfAbsent(loc, numberFormat);
69751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
69851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        numberFormat = (NumberFormat) numberFormat.clone();
69951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
70051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        initializeDefaultCentury();
70151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
70251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
70351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void initializeCalendar(Locale loc) {
70451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (calendar == null) {
70551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            assert loc != null;
70651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // The format object must be constructed using the symbols for this zone.
70751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // However, the calendar should use the current default TimeZone.
70851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // If this is not contained in the locale zone strings, then the zone
70951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // will be formatted using generic GMT+/-H:MM nomenclature.
71051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            calendar = Calendar.getInstance(TimeZone.getDefault(), loc);
71151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
71251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
71351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
71451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
71551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the compiled form of the given pattern. The syntax of
71651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * the compiled pattern is:
71751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <blockquote>
71851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * CompiledPattern:
71951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *     EntryList
72051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * EntryList:
72151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *     Entry
72251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *     EntryList Entry
72351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Entry:
72451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *     TagField
72551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *     TagField data
72651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * TagField:
72751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *     Tag Length
72851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *     TaggedData
72951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Tag:
73051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *     pattern_char_index
73151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *     TAG_QUOTE_CHARS
73251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Length:
73351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *     short_length
73451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *     long_length
73551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * TaggedData:
73651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *     TAG_QUOTE_ASCII_CHAR ascii_char
73751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
73851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * </blockquote>
73951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
74051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * where `short_length' is an 8-bit unsigned integer between 0 and
74151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * 254.  `long_length' is a sequence of an 8-bit integer 255 and a
74251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * 32-bit signed integer value which is split into upper and lower
74351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * 16-bit fields in two char's. `pattern_char_index' is an 8-bit
74451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * integer between 0 and 18. `ascii_char' is an 7-bit ASCII
74551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * character value. `data' depends on its Tag value.
74651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <p>
74751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * If Length is short_length, Tag and short_length are packed in a
74851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * single char, as illustrated below.
74951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <blockquote>
75051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *     char[0] = (Tag << 8) | short_length;
75151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * </blockquote>
75251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
75351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * If Length is long_length, Tag and 255 are packed in the first
75451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * char and a 32-bit integer, as illustrated below.
75551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <blockquote>
75651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *     char[0] = (Tag << 8) | 255;
75751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *     char[1] = (char) (long_length >>> 16);
75851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *     char[2] = (char) (long_length & 0xffff);
75951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * </blockquote>
76051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <p>
76151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * If Tag is a pattern_char_index, its Length is the number of
76251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * pattern characters. For example, if the given pattern is
76351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * "yyyy", Tag is 1 and Length is 4, followed by no data.
76451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <p>
76551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * If Tag is TAG_QUOTE_CHARS, its Length is the number of char's
76651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * following the TagField. For example, if the given pattern is
76751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * "'o''clock'", Length is 7 followed by a char sequence of
76851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>o&nbs;'&nbs;c&nbs;l&nbs;o&nbs;c&nbs;k</code>.
76951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <p>
77051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * TAG_QUOTE_ASCII_CHAR is a special tag and has an ASCII
77151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * character in place of Length. For example, if the given pattern
77251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * is "'o'", the TaggedData entry is
77351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>((TAG_QUOTE_ASCII_CHAR&nbs;<<&nbs;8)&nbs;|&nbs;'o')</code>.
77451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
77551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception NullPointerException if the given pattern is null
77651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception IllegalArgumentException if the given pattern is invalid
77751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
77851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private char[] compile(String pattern) {
77951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int length = pattern.length();
78051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        boolean inQuote = false;
781af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin        StringBuilder compiledCode = new StringBuilder(length * 2);
78251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        StringBuilder tmpBuffer = null;
78351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int count = 0;
78451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int lastTag = -1;
78551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
78651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = 0; i < length; i++) {
78751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            char c = pattern.charAt(i);
78851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
78951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (c == '\'') {
79051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // '' is treated as a single quote regardless of being
79151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // in a quoted section.
79251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if ((i + 1) < length) {
79351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    c = pattern.charAt(i + 1);
79451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (c == '\'') {
79551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        i++;
79651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        if (count != 0) {
797af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                            encode(lastTag, count, compiledCode);
79851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            lastTag = -1;
79951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            count = 0;
80051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        }
80151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        if (inQuote) {
80251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            tmpBuffer.append(c);
80351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        } else {
804af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                            compiledCode.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | c));
80551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        }
80651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        continue;
80751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
80851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
80951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (!inQuote) {
81051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (count != 0) {
811af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                        encode(lastTag, count, compiledCode);
81251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        lastTag = -1;
81351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        count = 0;
81451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
81551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (tmpBuffer == null) {
81651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        tmpBuffer = new StringBuilder(length);
81751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    } else {
81851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        tmpBuffer.setLength(0);
81951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
82051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    inQuote = true;
82151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                } else {
82251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    int len = tmpBuffer.length();
82351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (len == 1) {
82451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        char ch = tmpBuffer.charAt(0);
82551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        if (ch < 128) {
826af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                            compiledCode.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | ch));
82751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        } else {
828af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                            compiledCode.append((char)(TAG_QUOTE_CHARS << 8 | 1));
829af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                            compiledCode.append(ch);
83051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        }
83151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    } else {
832af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                        encode(TAG_QUOTE_CHARS, len, compiledCode);
833af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                        compiledCode.append(tmpBuffer);
83451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
83551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    inQuote = false;
83651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
83751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                continue;
83851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
83951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (inQuote) {
84051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                tmpBuffer.append(c);
84151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                continue;
84251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
84351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) {
84451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (count != 0) {
845af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                    encode(lastTag, count, compiledCode);
84651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    lastTag = -1;
84751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    count = 0;
84851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
84951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (c < 128) {
85051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // In most cases, c would be a delimiter, such as ':'.
851af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                    compiledCode.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | c));
85251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                } else {
85351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // Take any contiguous non-ASCII alphabet characters and
85451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // put them in a single TAG_QUOTE_CHARS.
85551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    int j;
85651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    for (j = i + 1; j < length; j++) {
85751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        char d = pattern.charAt(j);
85851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        if (d == '\'' || (d >= 'a' && d <= 'z' || d >= 'A' && d <= 'Z')) {
85951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            break;
86051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        }
86151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
862af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                    compiledCode.append((char)(TAG_QUOTE_CHARS << 8 | (j - i)));
86351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    for (; i < j; i++) {
864af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                        compiledCode.append(pattern.charAt(i));
86551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
86651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    i--;
86751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
86851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                continue;
86951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
87051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
87151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int tag;
87251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if ((tag = DateFormatSymbols.patternChars.indexOf(c)) == -1) {
87351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                throw new IllegalArgumentException("Illegal pattern character " +
87451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                   "'" + c + "'");
87551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
87651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (lastTag == -1 || lastTag == tag) {
87751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                lastTag = tag;
87851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                count++;
87951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                continue;
88051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
881af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin            encode(lastTag, count, compiledCode);
88251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            lastTag = tag;
88351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            count = 1;
88451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
88551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
88651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (inQuote) {
88751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IllegalArgumentException("Unterminated quote");
88851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
88951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
89051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (count != 0) {
891af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin            encode(lastTag, count, compiledCode);
89251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
89351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
89451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // Copy the compiled pattern to a char array
895af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin        int len = compiledCode.length();
89651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        char[] r = new char[len];
897af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin        compiledCode.getChars(0, len, r, 0);
89851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return r;
89951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
90051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
90151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
90251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Encodes the given tag and length and puts encoded char(s) into buffer.
90351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
9046e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin    private static void encode(int tag, int length, StringBuilder buffer) {
90551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (tag == PATTERN_ISO_ZONE && length >= 4) {
90651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IllegalArgumentException("invalid ISO 8601 format: length=" + length);
90751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
90851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (length < 255) {
90951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            buffer.append((char)(tag << 8 | length));
91051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {
91151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            buffer.append((char)((tag << 8) | 0xff));
91251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            buffer.append((char)(length >>> 16));
91351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            buffer.append((char)(length & 0xffff));
91451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
91551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
91651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
91751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* Initialize the fields we use to disambiguate ambiguous years. Separate
91851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * so we can call it from readObject().
91951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
92051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void initializeDefaultCentury() {
92151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        calendar.setTimeInMillis(System.currentTimeMillis());
92251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        calendar.add( Calendar.YEAR, -80 );
92351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        parseAmbiguousDatesAsAfter(calendar.getTime());
92451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
92551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
92651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* Define one-century window into which to disambiguate dates using
92751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * two-digit years.
92851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
92951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void parseAmbiguousDatesAsAfter(Date startDate) {
93051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        defaultCenturyStart = startDate;
93151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        calendar.setTime(startDate);
93251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        defaultCenturyStartYear = calendar.get(Calendar.YEAR);
93351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
93451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
93551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
93651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Sets the 100-year period 2-digit years will be interpreted as being in
93751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * to begin on the date the user specifies.
93851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
93951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param startDate During parsing, two digit years will be placed in the range
94051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>startDate</code> to <code>startDate + 100 years</code>.
94151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @see #get2DigitYearStart
94251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @since 1.2
94351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
94451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void set2DigitYearStart(Date startDate) {
94551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        parseAmbiguousDatesAsAfter(new Date(startDate.getTime()));
94651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
94751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
94851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
94951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the beginning date of the 100-year period 2-digit years are interpreted
95051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * as being within.
95151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
95251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the start of the 100-year period into which two digit years are
95351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * parsed
95451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @see #set2DigitYearStart
95551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @since 1.2
95651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
95751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public Date get2DigitYearStart() {
95851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return (Date) defaultCenturyStart.clone();
95951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
96051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
96151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
96251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Formats the given <code>Date</code> into a date/time string and appends
96351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * the result to the given <code>StringBuffer</code>.
96451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
96551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param date the date-time value to be formatted into a date-time string.
96651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param toAppendTo where the new date-time text is to be appended.
96751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param pos the formatting position. On input: an alignment field,
96851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * if desired. On output: the offsets of the alignment field.
96951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the formatted date-time string.
97051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception NullPointerException if the given {@code date} is {@code null}.
97151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
9726e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin    @Override
97351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public StringBuffer format(Date date, StringBuffer toAppendTo,
97451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                               FieldPosition pos)
97551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
97651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        pos.beginIndex = pos.endIndex = 0;
97751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return format(date, toAppendTo, pos.getFieldDelegate());
97851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
97951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
98051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // Called from Format after creating a FieldDelegate
98151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private StringBuffer format(Date date, StringBuffer toAppendTo,
98251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                FieldDelegate delegate) {
98351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // Convert input date to time field list
98451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        calendar.setTime(date);
98551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
98651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        boolean useDateFormatSymbols = useDateFormatSymbols();
98751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
98851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = 0; i < compiledPattern.length; ) {
98951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int tag = compiledPattern[i] >>> 8;
99051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int count = compiledPattern[i++] & 0xff;
99151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (count == 255) {
99251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                count = compiledPattern[i++] << 16;
99351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                count |= compiledPattern[i++];
99451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
99551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
99651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            switch (tag) {
99751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            case TAG_QUOTE_ASCII_CHAR:
99851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                toAppendTo.append((char)count);
99951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break;
100051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
100151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            case TAG_QUOTE_CHARS:
100251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                toAppendTo.append(compiledPattern, i, count);
100351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                i += count;
100451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break;
100551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
100651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            default:
100751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
100851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break;
100951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
101051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
101151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return toAppendTo;
101251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
101351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
101451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
101551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Formats an Object producing an <code>AttributedCharacterIterator</code>.
101651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * You can use the returned <code>AttributedCharacterIterator</code>
101751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * to build the resulting String, as well as to determine information
101851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * about the resulting String.
101951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <p>
102051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Each attribute key of the AttributedCharacterIterator will be of type
102151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>DateFormat.Field</code>, with the corresponding attribute value
102251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * being the same as the attribute key.
102351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
102451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception NullPointerException if obj is null.
102551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception IllegalArgumentException if the Format cannot format the
102651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *            given object, or if the Format's pattern string is invalid.
102751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param obj The object to format
102851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return AttributedCharacterIterator describing the formatted value.
102951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @since 1.4
103051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
10316e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin    @Override
103251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
103351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        StringBuffer sb = new StringBuffer();
103451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        CharacterIteratorFieldDelegate delegate = new
103551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                         CharacterIteratorFieldDelegate();
103651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
103751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (obj instanceof Date) {
103851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            format((Date)obj, sb, delegate);
103951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
104051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        else if (obj instanceof Number) {
104151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            format(new Date(((Number)obj).longValue()), sb, delegate);
104251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
104351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        else if (obj == null) {
104451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new NullPointerException(
104551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                   "formatToCharacterIterator must be passed non-null object");
104651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
104751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        else {
104851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IllegalArgumentException(
104951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                             "Cannot format given Object as a Date");
105051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
105151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return delegate.getIterator(sb.toString());
105251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
105351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
105451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // Map index into pattern character string to Calendar field number
10556e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin    private static final int[] PATTERN_INDEX_TO_CALENDAR_FIELD = {
10566e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Calendar.ERA,
10576e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Calendar.YEAR,
10586e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Calendar.MONTH,
10596e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Calendar.DATE,
10606e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Calendar.HOUR_OF_DAY,
10616e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Calendar.HOUR_OF_DAY,
10626e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Calendar.MINUTE,
10636e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Calendar.SECOND,
10646e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Calendar.MILLISECOND,
10656e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Calendar.DAY_OF_WEEK,
10666e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Calendar.DAY_OF_YEAR,
10676e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Calendar.DAY_OF_WEEK_IN_MONTH,
10686e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Calendar.WEEK_OF_YEAR,
10696e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Calendar.WEEK_OF_MONTH,
10706e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Calendar.AM_PM,
10716e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Calendar.HOUR,
10726e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Calendar.HOUR,
107351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        Calendar.ZONE_OFFSET,
10746e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Calendar.ZONE_OFFSET,
10756e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        CalendarBuilder.WEEK_YEAR,         // Pseudo Calendar field
10766e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        CalendarBuilder.ISO_DAY_OF_WEEK,   // Pseudo Calendar field
1077b7554f779d330037a5cf591fcc8be73db73a0384Narayan Kamath        Calendar.ZONE_OFFSET,
1078b7554f779d330037a5cf591fcc8be73db73a0384Narayan Kamath        Calendar.MONTH,
1079d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer        // Android-added: 'c' for standalone day of week.
108080339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        Calendar.DAY_OF_WEEK,
108180339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        // Android-added: Support for 'b'/'B' (day period). Calendar.AM_PM is just used as a
108280339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        // placeholder in the absence of full support for day period.
108380339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        Calendar.AM_PM,
108480339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        Calendar.AM_PM
108551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    };
108651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
108751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // Map index into pattern character string to DateFormat field number
108851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final int[] PATTERN_INDEX_TO_DATE_FORMAT_FIELD = {
10896e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.ERA_FIELD,
10906e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.YEAR_FIELD,
10916e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.MONTH_FIELD,
10926e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.DATE_FIELD,
10936e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.HOUR_OF_DAY1_FIELD,
10946e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.HOUR_OF_DAY0_FIELD,
10956e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.MINUTE_FIELD,
10966e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.SECOND_FIELD,
10976e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.MILLISECOND_FIELD,
10986e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.DAY_OF_WEEK_FIELD,
10996e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.DAY_OF_YEAR_FIELD,
11006e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD,
11016e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.WEEK_OF_YEAR_FIELD,
11026e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.WEEK_OF_MONTH_FIELD,
11036e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.AM_PM_FIELD,
11046e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.HOUR1_FIELD,
11056e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.HOUR0_FIELD,
11066e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.TIMEZONE_FIELD,
11076e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.TIMEZONE_FIELD,
11086e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.YEAR_FIELD,
11096e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        DateFormat.DAY_OF_WEEK_FIELD,
1110b7554f779d330037a5cf591fcc8be73db73a0384Narayan Kamath        DateFormat.TIMEZONE_FIELD,
1111b7554f779d330037a5cf591fcc8be73db73a0384Narayan Kamath        DateFormat.MONTH_FIELD,
1112d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer        // Android-added: 'c' for standalone day of week.
111380339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        DateFormat.DAY_OF_WEEK_FIELD,
111480339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        // Android-added: Support for 'b'/'B' (day period). DateFormat.AM_PM_FIELD is just used as a
111580339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        // placeholder in the absence of full support for day period.
111680339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        DateFormat.AM_PM_FIELD,
111780339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        DateFormat.AM_PM_FIELD
111851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    };
111951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
112051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // Maps from DecimalFormatSymbols index to Field constant
112151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static final Field[] PATTERN_INDEX_TO_DATE_FORMAT_FIELD_ID = {
11226e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.ERA,
11236e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.YEAR,
11246e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.MONTH,
11256e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.DAY_OF_MONTH,
11266e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.HOUR_OF_DAY1,
11276e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.HOUR_OF_DAY0,
11286e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.MINUTE,
11296e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.SECOND,
11306e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.MILLISECOND,
11316e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.DAY_OF_WEEK,
11326e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.DAY_OF_YEAR,
11336e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.DAY_OF_WEEK_IN_MONTH,
11346e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.WEEK_OF_YEAR,
11356e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.WEEK_OF_MONTH,
11366e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.AM_PM,
11376e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.HOUR1,
11386e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.HOUR0,
113951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        Field.TIME_ZONE,
11406e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.TIME_ZONE,
11416e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.YEAR,
11426e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Field.DAY_OF_WEEK,
1143b7554f779d330037a5cf591fcc8be73db73a0384Narayan Kamath        Field.TIME_ZONE,
1144b7554f779d330037a5cf591fcc8be73db73a0384Narayan Kamath        Field.MONTH,
1145d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer        // Android-added: 'c' for standalone day of week.
114680339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        Field.DAY_OF_WEEK,
114780339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        // Android-added: Support for 'b'/'B' (day period). Field.AM_PM is just used as a
114880339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        // placeholder in the absence of full support for day period.
114980339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        Field.AM_PM,
115080339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        Field.AM_PM
115151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    };
115251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
115351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
115451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Private member function that does the real date/time formatting.
115551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
115651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void subFormat(int patternCharIndex, int count,
115751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                           FieldDelegate delegate, StringBuffer buffer,
115851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                           boolean useDateFormatSymbols)
115951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
116051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int     maxIntCount = Integer.MAX_VALUE;
116151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        String  current = null;
116251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int     beginOffset = buffer.length();
116351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
116451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
116551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int value;
116651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (field == CalendarBuilder.WEEK_YEAR) {
116751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (calendar.isWeekDateSupported()) {
116851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                value = calendar.getWeekYear();
116951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            } else {
117051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // use calendar year 'y' instead
117151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                patternCharIndex = PATTERN_YEAR;
117251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
117351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                value = calendar.get(field);
117451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
117551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else if (field == CalendarBuilder.ISO_DAY_OF_WEEK) {
117651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            value = CalendarBuilder.toISODayOfWeek(calendar.get(Calendar.DAY_OF_WEEK));
117751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {
117851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            value = calendar.get(field);
117951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
118051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
118151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int style = (count >= 4) ? Calendar.LONG : Calendar.SHORT;
118251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (!useDateFormatSymbols && field != CalendarBuilder.ISO_DAY_OF_WEEK) {
118351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            current = calendar.getDisplayName(field, style, locale);
118451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
118551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
118651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // Note: zeroPaddingNumber() assumes that maxDigits is either
118751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // 2 or maxIntCount. If we make any changes to this,
118851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // zeroPaddingNumber() must be fixed.
118951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
119051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        switch (patternCharIndex) {
119151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        case PATTERN_ERA: // 'G'
119251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (useDateFormatSymbols) {
119351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                String[] eras = formatData.getEras();
11946e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                if (value < eras.length) {
119551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    current = eras[value];
11966e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                }
119751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
11986e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin            if (current == null) {
119951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                current = "";
12006e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin            }
120151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
120251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
120351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        case PATTERN_WEEK_YEAR: // 'Y'
120451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        case PATTERN_YEAR:      // 'y'
120551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (calendar instanceof GregorianCalendar) {
12066e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                if (count != 2) {
120751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    zeroPaddingNumber(value, count, maxIntCount, buffer);
1208af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                } else {
12096e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                    zeroPaddingNumber(value, 2, 2, buffer);
12106e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                } // clip 1996 to 96
121151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            } else {
121251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (current == null) {
121351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    zeroPaddingNumber(value, style == Calendar.LONG ? 1 : count,
121451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                      maxIntCount, buffer);
121551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
121651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
121751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
121851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12194c8d6d2a84cffba9a34ea03d534d77027fb1974ePaul Duffin        case PATTERN_MONTH: // 'M'
12207355fec3783cb45ef6770ce7969c1319347c8b6aJoachim Sauer            if (useDateFormatSymbols) {
12217355fec3783cb45ef6770ce7969c1319347c8b6aJoachim Sauer                current = formatMonth(count, value, maxIntCount, buffer, useDateFormatSymbols,
12227355fec3783cb45ef6770ce7969c1319347c8b6aJoachim Sauer                        false /* standalone */);
12237355fec3783cb45ef6770ce7969c1319347c8b6aJoachim Sauer            }
1224d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            break;
1225d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
1226af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin        case PATTERN_MONTH_STANDALONE: // 'L'
12277355fec3783cb45ef6770ce7969c1319347c8b6aJoachim Sauer            if (useDateFormatSymbols) {
12287355fec3783cb45ef6770ce7969c1319347c8b6aJoachim Sauer                current = formatMonth(count, value, maxIntCount, buffer, useDateFormatSymbols,
12297355fec3783cb45ef6770ce7969c1319347c8b6aJoachim Sauer                        true /* standalone */);
12307355fec3783cb45ef6770ce7969c1319347c8b6aJoachim Sauer            }
123151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
123251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
123351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        case PATTERN_HOUR_OF_DAY1: // 'k' 1-based.  eg, 23:59 + 1 hour =>> 24:59
123451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (current == null) {
12356e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                if (value == 0) {
12366e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                    zeroPaddingNumber(calendar.getMaximum(Calendar.HOUR_OF_DAY) + 1,
123751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                      count, maxIntCount, buffer);
12386e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                } else {
123951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    zeroPaddingNumber(value, count, maxIntCount, buffer);
12406e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                }
124151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
124251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
124351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12444c8d6d2a84cffba9a34ea03d534d77027fb1974ePaul Duffin        case PATTERN_DAY_OF_WEEK: // 'E'
12457355fec3783cb45ef6770ce7969c1319347c8b6aJoachim Sauer            if (current == null) {
1246d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer                // Android-changed: extract formatWeekday() method.
12477355fec3783cb45ef6770ce7969c1319347c8b6aJoachim Sauer                current = formatWeekday(count, value, useDateFormatSymbols, false /* standalone */);
12487355fec3783cb45ef6770ce7969c1319347c8b6aJoachim Sauer            }
1249d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            break;
1250d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
1251d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer        // BEGIN Android-added: support for 'c' (standalone day of week).
12524c8d6d2a84cffba9a34ea03d534d77027fb1974ePaul Duffin        case PATTERN_STANDALONE_DAY_OF_WEEK: // 'c'
12537355fec3783cb45ef6770ce7969c1319347c8b6aJoachim Sauer            if (current == null) {
1254d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer                // Android-changed: extract formatWeekday() method.
12557355fec3783cb45ef6770ce7969c1319347c8b6aJoachim Sauer                current = formatWeekday(count, value, useDateFormatSymbols, true /* standalone */);
12567355fec3783cb45ef6770ce7969c1319347c8b6aJoachim Sauer            }
125751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
1258d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer        // END Android-added: support for 'c' (standalone day of week).
125951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
126051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        case PATTERN_AM_PM:    // 'a'
126151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (useDateFormatSymbols) {
126251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                String[] ampm = formatData.getAmPmStrings();
126351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                current = ampm[value];
126451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
126551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
126651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
126780339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        // Android-added: Ignore 'b' and 'B' introduced in CLDR 32+ pattern data. http://b/68139386
126880339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        // Not currently supported here.
126980339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        case PATTERN_DAY_PERIOD:
127080339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang        case PATTERN_FLEXIBLE_DAY_PERIOD:
127180339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang            current = "";
127280339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang            break;
127380339f4741bb174f9c6148b843ac0dcfc6422306Victor Chang
127451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        case PATTERN_HOUR1:    // 'h' 1-based.  eg, 11PM + 1 hour =>> 12 AM
127551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (current == null) {
12766e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                if (value == 0) {
12776e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                    zeroPaddingNumber(calendar.getLeastMaximum(Calendar.HOUR) + 1,
127851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                      count, maxIntCount, buffer);
12796e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                } else {
128051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    zeroPaddingNumber(value, count, maxIntCount, buffer);
12816e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                }
128251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
128351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
128451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
128551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        case PATTERN_ZONE_NAME: // 'z'
128651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (current == null) {
1287d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer                // BEGIN Android-changed: format time zone name using ICU.
12889c853c5b9ebbb0ef60a013ae10ee411d70dfa832Piotr Jastrzebski                TimeZone tz = calendar.getTimeZone();
12899c853c5b9ebbb0ef60a013ae10ee411d70dfa832Piotr Jastrzebski                boolean daylight = (calendar.get(Calendar.DST_OFFSET) != 0);
1290d8bef3c23bf1851242cc2dc189edaa544eeabe58Joachim Sauer                String zoneString;
1291d8bef3c23bf1851242cc2dc189edaa544eeabe58Joachim Sauer                if (formatData.isZoneStringsSet) {
12924947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                    // DateFormatSymbols.setZoneStrings() has be used, use those values instead of
12934947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                    // ICU code.
12944947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                    int tzstyle = count < 4 ? TimeZone.SHORT : TimeZone.LONG;
12954947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                    zoneString = libcore.icu.TimeZoneNames.getDisplayName(
1296d8bef3c23bf1851242cc2dc189edaa544eeabe58Joachim Sauer                            formatData.getZoneStringsWrapper(), tz.getID(), daylight, tzstyle);
1297d8bef3c23bf1851242cc2dc189edaa544eeabe58Joachim Sauer                } else {
1298fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                    TimeZoneNames.NameType nameType;
1299fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                    if (count < 4) {
1300fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                        nameType = daylight
1301fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                                ? TimeZoneNames.NameType.SHORT_DAYLIGHT
1302fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                                : TimeZoneNames.NameType.SHORT_STANDARD;
13034947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                    } else {
1304fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                        nameType = daylight
1305fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                                ? TimeZoneNames.NameType.LONG_DAYLIGHT
1306fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                                : TimeZoneNames.NameType.LONG_STANDARD;
13074947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                    }
1308fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                    String canonicalID = android.icu.util.TimeZone.getCanonicalID(tz.getID());
1309fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                    zoneString = getTimeZoneNames()
1310fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                            .getDisplayName(canonicalID, nameType, calendar.getTimeInMillis());
1311d8bef3c23bf1851242cc2dc189edaa544eeabe58Joachim Sauer                }
13129c853c5b9ebbb0ef60a013ae10ee411d70dfa832Piotr Jastrzebski                if (zoneString != null) {
13139c853c5b9ebbb0ef60a013ae10ee411d70dfa832Piotr Jastrzebski                    buffer.append(zoneString);
131451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                } else {
13159c853c5b9ebbb0ef60a013ae10ee411d70dfa832Piotr Jastrzebski                    int offsetMillis = calendar.get(Calendar.ZONE_OFFSET) +
13169c853c5b9ebbb0ef60a013ae10ee411d70dfa832Piotr Jastrzebski                        calendar.get(Calendar.DST_OFFSET);
13179c853c5b9ebbb0ef60a013ae10ee411d70dfa832Piotr Jastrzebski                    buffer.append(TimeZone.createGmtOffsetString(true, true, offsetMillis));
131851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
1319d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer                // END Android-changed: format time zone name using ICU.
132051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
132151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
132251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
132351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        case PATTERN_ZONE_VALUE: // 'Z' ("-/+hhmm" form)
1324c99342bb4ce22d842e806d9ebf2f9fcc761c05fbTobias Thierer        // BEGIN Android-changed: use shared code in TimeZone for zone offset string.
1325d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        {
1326d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            value = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
1327d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            final boolean includeSeparator = (count >= 4);
1328d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            final boolean includeGmt = (count == 4);
1329d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            buffer.append(TimeZone.createGmtOffsetString(includeGmt, includeSeparator, value));
133051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
133151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
1332d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        }
1333c99342bb4ce22d842e806d9ebf2f9fcc761c05fbTobias Thierer        // END Android-changed: use shared code in TimeZone for zone offset string.
133451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
133551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        case PATTERN_ISO_ZONE:   // 'X'
133651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            value = calendar.get(Calendar.ZONE_OFFSET)
133751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    + calendar.get(Calendar.DST_OFFSET);
133851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
133951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (value == 0) {
134051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                buffer.append('Z');
134151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break;
134251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
134351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
134451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            value /=  60000;
134551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (value >= 0) {
134651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                buffer.append('+');
134751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            } else {
134851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                buffer.append('-');
134951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                value = -value;
135051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
135151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
135251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            CalendarUtils.sprintf0d(buffer, value / 60, 2);
135351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (count == 1) {
135451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break;
135551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
135651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
135751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (count == 3) {
135851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                buffer.append(':');
135951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
136051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            CalendarUtils.sprintf0d(buffer, value % 60, 2);
136151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
1362d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer        // BEGIN Android-added: Better UTS#35 conformity for fractional seconds.
1363afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath        case PATTERN_MILLISECOND: // 'S'
1364afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath            // Fractional seconds must be treated specially. We must always convert the parsed
1365afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath            // value into a fractional second [0, 1) and then widen it out to the appropriate
1366afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath            // formatted size. For example, an initial value of 789 will be converted
1367afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath            // 0.789 and then become ".7" (S) or ".78" (SS) or "0.789" (SSS) or "0.7890" (SSSS)
1368afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath            // in the resulting formatted output.
1369afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath            if (current == null) {
1370afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath                value = (int) (((double) value / 1000) * Math.pow(10, count));
1371afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath                zeroPaddingNumber(value, count, count, buffer);
1372afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath            }
1373afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath            break;
1374d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer        // END Android-added: Better UTS#35 conformity for fractional seconds.
137551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
137651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        default:
137751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     // case PATTERN_DAY_OF_MONTH:         // 'd'
137851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     // case PATTERN_HOUR_OF_DAY0:         // 'H' 0-based.  eg, 23:59 + 1 hour =>> 00:59
137951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     // case PATTERN_MINUTE:               // 'm'
138051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     // case PATTERN_SECOND:               // 's'
1381d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer     // Android-removed: PATTERN_MILLISECONDS handled in an explicit case above.
1382d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer     //// case PATTERN_MILLISECOND:          // 'S'
138351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     // case PATTERN_DAY_OF_YEAR:          // 'D'
138451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     // case PATTERN_DAY_OF_WEEK_IN_MONTH: // 'F'
138551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     // case PATTERN_WEEK_OF_YEAR:         // 'w'
138651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     // case PATTERN_WEEK_OF_MONTH:        // 'W'
138751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     // case PATTERN_HOUR0:                // 'K' eg, 11PM + 1 hour =>> 0 AM
138851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     // case PATTERN_ISO_DAY_OF_WEEK:      // 'u' pseudo field, Monday = 1, ..., Sunday = 7
138951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (current == null) {
139051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                zeroPaddingNumber(value, count, maxIntCount, buffer);
139151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
139251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            break;
139351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } // switch (patternCharIndex)
139451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
139551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (current != null) {
139651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            buffer.append(current);
139751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
139851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
139951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int fieldID = PATTERN_INDEX_TO_DATE_FORMAT_FIELD[patternCharIndex];
140051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        Field f = PATTERN_INDEX_TO_DATE_FORMAT_FIELD_ID[patternCharIndex];
140151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
140251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        delegate.formatted(fieldID, f, f, beginOffset, buffer.length(), buffer);
140351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
140451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
1405d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer    // BEGIN Android-added: formatWeekday and formatMonth methods to format using ICU data.
1406d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath    private String formatWeekday(int count, int value, boolean useDateFormatSymbols,
1407d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                                 boolean standalone) {
1408d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        if (useDateFormatSymbols) {
1409d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            final String[] weekdays;
1410d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            if (count == 4) {
1411d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                weekdays = standalone ? formatData.getStandAloneWeekdays() : formatData.getWeekdays();
1412d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            } else if (count == 5) {
1413d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                weekdays =
1414d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                        standalone ? formatData.getTinyStandAloneWeekdays() : formatData.getTinyWeekdays();
1415d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
1416d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            } else { // count < 4, use abbreviated form if exists
1417d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                weekdays = standalone ? formatData.getShortStandAloneWeekdays() : formatData.getShortWeekdays();
1418d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            }
1419d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
1420d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            return weekdays[value];
1421d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        }
1422d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
1423d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        return null;
1424d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath    }
1425d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
1426d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath    private String formatMonth(int count, int value, int maxIntCount, StringBuffer buffer,
1427d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                               boolean useDateFormatSymbols, boolean standalone) {
1428d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        String current = null;
1429d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        if (useDateFormatSymbols) {
1430d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            final String[] months;
1431d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            if (count == 4) {
1432d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                months = standalone ? formatData.getStandAloneMonths() : formatData.getMonths();
1433d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            } else if (count == 5) {
1434d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                months = standalone ? formatData.getTinyStandAloneMonths() : formatData.getTinyMonths();
1435d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            } else if (count == 3) {
1436d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                months = standalone ? formatData.getShortStandAloneMonths() : formatData.getShortMonths();
1437d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            } else {
1438d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                months = null;
1439d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            }
1440d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
1441d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            if (months != null) {
1442d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                current = months[value];
1443d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            }
1444d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        } else {
1445d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            if (count < 3) {
1446d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                current = null;
1447d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            }
1448d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        }
1449d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
1450d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        if (current == null) {
1451d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            zeroPaddingNumber(value+1, count, maxIntCount, buffer);
1452d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        }
1453d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
1454d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        return current;
1455d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath    }
1456d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer    // END Android-added: formatWeekday and formatMonth methods to format using ICU data.
1457d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
145851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
145951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Formats a number with the specified minimum and maximum number of digits.
146051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
14616e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin    private void zeroPaddingNumber(int value, int minDigits, int maxDigits, StringBuffer buffer)
146251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
146351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // Optimization for 1, 2 and 4 digit numbers. This should
146451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // cover most cases of formatting date/time related items.
146551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // Note: This optimization code assumes that maxDigits is
146651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // either 2 or Integer.MAX_VALUE (maxIntCount in format()).
146751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        try {
146851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (zeroDigit == 0) {
146951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                zeroDigit = ((DecimalFormat)numberFormat).getDecimalFormatSymbols().getZeroDigit();
147051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
147151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (value >= 0) {
147251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (value < 100 && minDigits >= 1 && minDigits <= 2) {
147351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (value < 10) {
147451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        if (minDigits == 2) {
147551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            buffer.append(zeroDigit);
147651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        }
147751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        buffer.append((char)(zeroDigit + value));
147851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    } else {
147951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        buffer.append((char)(zeroDigit + value / 10));
148051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        buffer.append((char)(zeroDigit + value % 10));
148151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
148251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return;
148351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                } else if (value >= 1000 && value < 10000) {
148451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (minDigits == 4) {
148551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        buffer.append((char)(zeroDigit + value / 1000));
148651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        value %= 1000;
148751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        buffer.append((char)(zeroDigit + value / 100));
148851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        value %= 100;
148951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        buffer.append((char)(zeroDigit + value / 10));
149051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        buffer.append((char)(zeroDigit + value % 10));
149151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        return;
149251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
149351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (minDigits == 2 && maxDigits == 2) {
149451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        zeroPaddingNumber(value % 100, 2, 2, buffer);
149551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        return;
149651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
149751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
149851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
149951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } catch (Exception e) {
150051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
150151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
150251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        numberFormat.setMinimumIntegerDigits(minDigits);
150351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        numberFormat.setMaximumIntegerDigits(maxDigits);
150451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        numberFormat.format((long)value, buffer, DontCareFieldPosition.INSTANCE);
150551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
150651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
150751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
150851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
150951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Parses text from a string to produce a <code>Date</code>.
151051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <p>
151151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * The method attempts to parse text starting at the index given by
151251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>pos</code>.
151351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * If parsing succeeds, then the index of <code>pos</code> is updated
151451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * to the index after the last character used (parsing does not necessarily
151551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * use all characters up to the end of the string), and the parsed
151651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * date is returned. The updated <code>pos</code> can be used to
151751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * indicate the starting point for the next call to this method.
151851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * If an error occurs, then the index of <code>pos</code> is not
151951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * changed, the error index of <code>pos</code> is set to the index of
152051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * the character where the error occurred, and null is returned.
152151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
152251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <p>This parsing operation uses the {@link DateFormat#calendar
152351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * calendar} to produce a {@code Date}. All of the {@code
152451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * calendar}'s date-time fields are {@linkplain Calendar#clear()
152551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * cleared} before parsing, and the {@code calendar}'s default
152651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * values of the date-time fields are used for any missing
152751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * date-time information. For example, the year value of the
152851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * parsed {@code Date} is 1970 with {@link GregorianCalendar} if
152951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * no year value is given from the parsing operation.  The {@code
153051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * TimeZone} value may be overwritten, depending on the given
153151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * pattern and the time zone value in {@code text}. Any {@code
153251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * TimeZone} value that has previously been set by a call to
153351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * {@link #setTimeZone(java.util.TimeZone) setTimeZone} may need
153451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * to be restored for further operations.
153551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
153651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param text  A <code>String</code>, part of which should be parsed.
153751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param pos   A <code>ParsePosition</code> object with index and error
153851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *              index information as described above.
153951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return A <code>Date</code> parsed from the string. In case of
154051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *         error, returns null.
154151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception NullPointerException if <code>text</code> or <code>pos</code> is null.
154251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
15436e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin    @Override
15442015e08d682be61dacd76c51bb0345f357fc4e96Narayan Kamath    public Date parse(String text, ParsePosition pos) {
1545d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer        // BEGIN Android-changed: extract parseInternal() and avoid modifying timezone during parse.
15462015e08d682be61dacd76c51bb0345f357fc4e96Narayan Kamath        // Make sure the timezone associated with this dateformat instance (set via
15472015e08d682be61dacd76c51bb0345f357fc4e96Narayan Kamath        // {@code setTimeZone} isn't change as a side-effect of parsing a date.
15482015e08d682be61dacd76c51bb0345f357fc4e96Narayan Kamath        final TimeZone tz = getTimeZone();
15492015e08d682be61dacd76c51bb0345f357fc4e96Narayan Kamath        try {
15502015e08d682be61dacd76c51bb0345f357fc4e96Narayan Kamath            return parseInternal(text, pos);
15512015e08d682be61dacd76c51bb0345f357fc4e96Narayan Kamath        } finally {
15522015e08d682be61dacd76c51bb0345f357fc4e96Narayan Kamath            setTimeZone(tz);
15532015e08d682be61dacd76c51bb0345f357fc4e96Narayan Kamath        }
15542015e08d682be61dacd76c51bb0345f357fc4e96Narayan Kamath    }
15552015e08d682be61dacd76c51bb0345f357fc4e96Narayan Kamath
15562015e08d682be61dacd76c51bb0345f357fc4e96Narayan Kamath    private Date parseInternal(String text, ParsePosition pos)
155751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
1558d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer        // END Android-changed: extract parseInternal() and avoid modifying timezone during parse.
155951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        checkNegativeNumberExpression();
156051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
156151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int start = pos.index;
156251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int oldStart = start;
156351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int textLength = text.length();
156451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
156551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        boolean[] ambiguousYear = {false};
156651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
156751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        CalendarBuilder calb = new CalendarBuilder();
156851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
156951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = 0; i < compiledPattern.length; ) {
157051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int tag = compiledPattern[i] >>> 8;
157151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int count = compiledPattern[i++] & 0xff;
157251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (count == 255) {
157351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                count = compiledPattern[i++] << 16;
157451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                count |= compiledPattern[i++];
157551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
157651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
157751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            switch (tag) {
157851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            case TAG_QUOTE_ASCII_CHAR:
157951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (start >= textLength || text.charAt(start) != (char)count) {
158051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    pos.index = oldStart;
158151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    pos.errorIndex = start;
158251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return null;
158351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
158451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                start++;
158551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break;
158651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
158751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            case TAG_QUOTE_CHARS:
158851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                while (count-- > 0) {
158951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (start >= textLength || text.charAt(start) != compiledPattern[i++]) {
159051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        pos.index = oldStart;
159151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        pos.errorIndex = start;
159251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        return null;
159351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
159451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    start++;
159551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
159651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break;
159751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
159851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            default:
159951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // Peek the next pattern to determine if we need to
160051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // obey the number of pattern letters for
160151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // parsing. It's required when parsing contiguous
160251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // digit text (e.g., "20010704") with a pattern which
160351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // has no delimiters between fields, like "yyyyMMdd".
160451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                boolean obeyCount = false;
160551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
160651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // In Arabic, a minus sign for a negative number is put after
160751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // the number. Even in another locale, a minus sign can be
160851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // put after a number using DateFormat.setNumberFormat().
160951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // If both the minus sign and the field-delimiter are '-',
161051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // subParse() needs to determine whether a '-' after a number
161151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // in the given text is a delimiter or is a minus sign for the
161251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // preceding number. We give subParse() a clue based on the
161351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // information in compiledPattern.
161451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                boolean useFollowingMinusSignAsDelimiter = false;
161551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
161651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (i < compiledPattern.length) {
161751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    int nextTag = compiledPattern[i] >>> 8;
161851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (!(nextTag == TAG_QUOTE_ASCII_CHAR ||
161951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                          nextTag == TAG_QUOTE_CHARS)) {
162051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        obeyCount = true;
162151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
162251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
162351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (hasFollowingMinusSign &&
162451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        (nextTag == TAG_QUOTE_ASCII_CHAR ||
162551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                         nextTag == TAG_QUOTE_CHARS)) {
162651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        int c;
162751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        if (nextTag == TAG_QUOTE_ASCII_CHAR) {
162851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            c = compiledPattern[i] & 0xff;
162951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        } else {
163051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            c = compiledPattern[i+1];
163151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        }
163251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
163351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        if (c == minusSign) {
163451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            useFollowingMinusSignAsDelimiter = true;
163551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        }
163651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
163751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
163851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                start = subParse(text, start, tag, count, obeyCount,
163951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                 ambiguousYear, pos,
164051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                 useFollowingMinusSignAsDelimiter, calb);
164151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (start < 0) {
164251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    pos.index = oldStart;
164351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return null;
164451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
164551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
164651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
164751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
164851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // At this point the fields of Calendar have been set.  Calendar
164951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // will fill in default values for missing fields when the time
165051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // is computed.
165151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
165251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        pos.index = start;
165351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
165451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        Date parsedDate;
165551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        try {
165651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            parsedDate = calb.establish(calendar).getTime();
165751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // If the year value is ambiguous,
165851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // then the two-digit year == the default start year
165951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (ambiguousYear[0]) {
166051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (parsedDate.before(defaultCenturyStart)) {
166151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    parsedDate = calb.addYear(100).establish(calendar).getTime();
166251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
166351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
166451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
166551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // An IllegalArgumentException will be thrown by Calendar.getTime()
166651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // if any fields are out of range, e.g., MONTH == 17.
166751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        catch (IllegalArgumentException e) {
166851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            pos.errorIndex = start;
166951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            pos.index = oldStart;
167051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return null;
167151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
167251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
167351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return parsedDate;
167451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
167551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
167651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
167751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Private code-size reduction function used by subParse.
167851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param text the time text being parsed.
167951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param start where to start parsing.
168051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param field the date field being parsed.
168151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param data the string array to parsed.
168251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the new start position if matching succeeded; a negative number
168351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * indicating matching failure, otherwise.
168451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
168551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private int matchString(String text, int start, int field, String[] data, CalendarBuilder calb)
168651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
168751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int i = 0;
168851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int count = data.length;
168951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
16906e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        if (field == Calendar.DAY_OF_WEEK) {
16916e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin            i = 1;
16926e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        }
169351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
169451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // There may be multiple strings in the data[] array which begin with
169551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
169651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // We keep track of the longest match, and return that.  Note that this
169751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // unfortunately requires us to test all array elements.
169851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int bestMatchLength = 0, bestMatch = -1;
169951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (; i<count; ++i)
170051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        {
170151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int length = data[i].length();
170251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // Always compare if we have no match yet; otherwise only compare
170351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // against potentially better matches (longer strings).
170451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (length > bestMatchLength &&
170551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                text.regionMatches(true, start, data[i], 0, length))
170651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            {
170751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                bestMatch = i;
170851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                bestMatchLength = length;
170951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
171000617c74e1f95fbe088f078341d607132575b0d6Narayan Kamath
1711d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer            // BEGIN Android-changed: Handle abbreviated fields that end with a '.'.
171200617c74e1f95fbe088f078341d607132575b0d6Narayan Kamath            // When the input option ends with a period (usually an abbreviated form), attempt
171300617c74e1f95fbe088f078341d607132575b0d6Narayan Kamath            // to match all chars up to that period.
171400617c74e1f95fbe088f078341d607132575b0d6Narayan Kamath            if ((data[i].charAt(length - 1) == '.') &&
171500617c74e1f95fbe088f078341d607132575b0d6Narayan Kamath                    ((length - 1) > bestMatchLength) &&
171600617c74e1f95fbe088f078341d607132575b0d6Narayan Kamath                    text.regionMatches(true, start, data[i], 0, length - 1)) {
171700617c74e1f95fbe088f078341d607132575b0d6Narayan Kamath                bestMatch = i;
171800617c74e1f95fbe088f078341d607132575b0d6Narayan Kamath                bestMatchLength = (length - 1);
171900617c74e1f95fbe088f078341d607132575b0d6Narayan Kamath            }
1720d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer            // END Android-changed: Handle abbreviated fields that end with a '.'.
172151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
172251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (bestMatch >= 0)
172351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        {
172451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            calb.set(field, bestMatch);
172551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return start + bestMatchLength;
172651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
172751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return -start;
172851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
172951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
173051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
173151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Performs the same thing as matchString(String, int, int,
173251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * String[]). This method takes a Map<String, Integer> instead of
173351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * String[].
173451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
173551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private int matchString(String text, int start, int field,
173651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            Map<String,Integer> data, CalendarBuilder calb) {
173751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (data != null) {
173851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            String bestMatch = null;
173951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
174051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            for (String name : data.keySet()) {
174151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                int length = name.length();
174251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (bestMatch == null || length > bestMatch.length()) {
174351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (text.regionMatches(true, start, name, 0, length)) {
174451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        bestMatch = name;
174551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
174651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
174751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
174851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
174951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (bestMatch != null) {
175051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                calb.set(field, data.get(bestMatch));
175151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return start + bestMatch.length();
175251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
175351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
175451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return -start;
175551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
175651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
175751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private int matchZoneString(String text, int start, String[] zoneNames) {
175851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = 1; i <= 4; ++i) {
175951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // Checking long and short zones [1 & 2],
176051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // and long and short daylight [3 & 4].
176151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            String zoneName = zoneNames[i];
176251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (text.regionMatches(true, start,
176351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                   zoneName, 0, zoneName.length())) {
176451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return i;
176551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
176651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
176751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return -1;
176851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
176951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
1770d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer    // Android-removed: unused private method matchDSTString.
1771d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer
1772d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer    // BEGIN Android-changed: Parse time zone strings using ICU TimeZoneNames.
1773d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer    // Note that this change falls back to the upstream zone names parsing code if the zoneStrings
1774d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer    // for the formatData field has been set by the user. The original code of subParseZoneString
1775d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer    // can be found in subParseZoneStringFromSymbols().
17764947038a7acb466855746df19d41ef26be507aa4Joachim Sauer    /**
17774947038a7acb466855746df19d41ef26be507aa4Joachim Sauer     * Parses the string in {@code text} (starting at {@code start}), interpreting it as a time zone
17784947038a7acb466855746df19d41ef26be507aa4Joachim Sauer     * name. If a time zone is found, the internal calendar is set to that timezone and the index of
17794947038a7acb466855746df19d41ef26be507aa4Joachim Sauer     * the first character after the time zone name is returned. Otherwise, returns {@code 0}.
17804947038a7acb466855746df19d41ef26be507aa4Joachim Sauer     * @return the index of the next character to parse or {@code 0} on error.
17814947038a7acb466855746df19d41ef26be507aa4Joachim Sauer     */
17824947038a7acb466855746df19d41ef26be507aa4Joachim Sauer    private int subParseZoneString(String text, int start, CalendarBuilder calb) {
17834947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        if (formatData.isZoneStringsSet) {
17844947038a7acb466855746df19d41ef26be507aa4Joachim Sauer            // DateFormatSymbols.setZoneStrings() has be used, use those values instead of ICU code.
17854947038a7acb466855746df19d41ef26be507aa4Joachim Sauer            return subParseZoneStringFromSymbols(text, start, calb);
17864947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        } else {
17874947038a7acb466855746df19d41ef26be507aa4Joachim Sauer            return subParseZoneStringFromICU(text, start, calb);
17884947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        }
17894947038a7acb466855746df19d41ef26be507aa4Joachim Sauer    }
17904947038a7acb466855746df19d41ef26be507aa4Joachim Sauer
17914947038a7acb466855746df19d41ef26be507aa4Joachim Sauer    private TimeZoneNames getTimeZoneNames() {
17924947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        if (timeZoneNames == null) {
17934947038a7acb466855746df19d41ef26be507aa4Joachim Sauer            timeZoneNames = TimeZoneNames.getInstance(locale);
179451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
17954947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        return timeZoneNames;
179651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
179751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
179851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
17994947038a7acb466855746df19d41ef26be507aa4Joachim Sauer     * The set of name types accepted when parsing time zone names.
180051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
18014947038a7acb466855746df19d41ef26be507aa4Joachim Sauer    private static final EnumSet<TimeZoneNames.NameType> NAME_TYPES =
18024947038a7acb466855746df19d41ef26be507aa4Joachim Sauer            EnumSet.of(TimeZoneNames.NameType.LONG_GENERIC, TimeZoneNames.NameType.LONG_STANDARD,
18034947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                    TimeZoneNames.NameType.LONG_DAYLIGHT, TimeZoneNames.NameType.SHORT_GENERIC,
18044947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                    TimeZoneNames.NameType.SHORT_STANDARD, TimeZoneNames.NameType.SHORT_DAYLIGHT);
18054947038a7acb466855746df19d41ef26be507aa4Joachim Sauer
18064947038a7acb466855746df19d41ef26be507aa4Joachim Sauer    /**
18074947038a7acb466855746df19d41ef26be507aa4Joachim Sauer     * Time zone name types that indicate daylight saving time.
18084947038a7acb466855746df19d41ef26be507aa4Joachim Sauer     */
18094947038a7acb466855746df19d41ef26be507aa4Joachim Sauer    private static final Set<TimeZoneNames.NameType> DST_NAME_TYPES =
18104947038a7acb466855746df19d41ef26be507aa4Joachim Sauer            Collections.unmodifiableSet(EnumSet.of(
18114947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                    TimeZoneNames.NameType.LONG_DAYLIGHT, TimeZoneNames.NameType.SHORT_DAYLIGHT));
18124947038a7acb466855746df19d41ef26be507aa4Joachim Sauer
18134947038a7acb466855746df19d41ef26be507aa4Joachim Sauer    /**
18144947038a7acb466855746df19d41ef26be507aa4Joachim Sauer     * Parses the time zone string using the ICU4J class {@link TimeZoneNames}.
18154947038a7acb466855746df19d41ef26be507aa4Joachim Sauer     */
18164947038a7acb466855746df19d41ef26be507aa4Joachim Sauer    private int subParseZoneStringFromICU(String text, int start, CalendarBuilder calb) {
18174947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        String currentTimeZoneID = android.icu.util.TimeZone.getCanonicalID(getTimeZone().getID());
18184947038a7acb466855746df19d41ef26be507aa4Joachim Sauer
18194947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        TimeZoneNames tzNames = getTimeZoneNames();
18204947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        TimeZoneNames.MatchInfo bestMatch = null;
18214947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        // The MetaZones associated with the current time zone are needed in two places, both of
18224947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        // which are avoided in some cases, so they are computed lazily.
18234947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        Set<String> currentTzMetaZoneIds = null;
18244947038a7acb466855746df19d41ef26be507aa4Joachim Sauer
1825fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller        Collection<TimeZoneNames.MatchInfo> matches = tzNames.find(text, start, NAME_TYPES);
1826fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller        for (TimeZoneNames.MatchInfo match : matches) {
1827fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller            if (bestMatch == null || bestMatch.matchLength() < match.matchLength()) {
1828fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                bestMatch = match;
1829fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller            } else if (bestMatch.matchLength() == match.matchLength()) {
1830fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                if (currentTimeZoneID.equals(match.tzID())) {
1831fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                    // Prefer the currently set timezone over other matches, even if they are
1832fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                    // the same length.
18334947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                    bestMatch = match;
1834fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                    break;
1835fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                } else if (match.mzID() != null) {
1836fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                    if (currentTzMetaZoneIds == null) {
1837fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                        currentTzMetaZoneIds =
1838fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                                tzNames.getAvailableMetaZoneIDs(currentTimeZoneID);
1839fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                    }
1840fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller                    if (currentTzMetaZoneIds.contains(match.mzID())) {
18414947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                        bestMatch = match;
18424947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                        break;
18434947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                    }
18444947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                }
18454947038a7acb466855746df19d41ef26be507aa4Joachim Sauer            }
1846fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller        }
1847fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller        if (bestMatch == null) {
1848fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller            // No match found, return error.
1849fb1a78d35d56cc48cc5ec5503d2bfff3406b923fNeil Fuller            return -start;
18504947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        }
18514947038a7acb466855746df19d41ef26be507aa4Joachim Sauer
18524947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        String tzId = bestMatch.tzID();
18534947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        if (tzId == null) {
18544947038a7acb466855746df19d41ef26be507aa4Joachim Sauer            if (currentTzMetaZoneIds == null) {
18554947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                currentTzMetaZoneIds = tzNames.getAvailableMetaZoneIDs(currentTimeZoneID);
18564947038a7acb466855746df19d41ef26be507aa4Joachim Sauer            }
18574947038a7acb466855746df19d41ef26be507aa4Joachim Sauer            if (currentTzMetaZoneIds.contains(bestMatch.mzID())) {
18584947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                tzId = currentTimeZoneID;
18594947038a7acb466855746df19d41ef26be507aa4Joachim Sauer            } else {
18604947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                // Match was for a meta-zone, find the matching reference zone.
18614947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                ULocale uLocale = ULocale.forLocale(locale);
18624947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                String region = uLocale.getCountry();
18634947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                if (region.length() == 0) {
18644947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                    uLocale = ULocale.addLikelySubtags(uLocale);
18654947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                    region = uLocale.getCountry();
18664947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                }
18674947038a7acb466855746df19d41ef26be507aa4Joachim Sauer                tzId = tzNames.getReferenceZoneID(bestMatch.mzID(), region);
18684947038a7acb466855746df19d41ef26be507aa4Joachim Sauer            }
18694947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        }
18704947038a7acb466855746df19d41ef26be507aa4Joachim Sauer
18714947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        TimeZone newTimeZone = TimeZone.getTimeZone(tzId);
18724947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        if (!currentTimeZoneID.equals(tzId)) {
18734947038a7acb466855746df19d41ef26be507aa4Joachim Sauer            setTimeZone(newTimeZone);
18744947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        }
18754947038a7acb466855746df19d41ef26be507aa4Joachim Sauer
18764947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        // Same logic as in subParseZoneStringFromSymbols, see below for details.
18774947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        boolean isDst = DST_NAME_TYPES.contains(bestMatch.nameType());
18784947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        int dstAmount = isDst ? newTimeZone.getDSTSavings() : 0;
18794947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        if (!isDst || dstAmount != 0) {
18804947038a7acb466855746df19d41ef26be507aa4Joachim Sauer            calb.clear(Calendar.ZONE_OFFSET).set(Calendar.DST_OFFSET, dstAmount);
18814947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        }
18824947038a7acb466855746df19d41ef26be507aa4Joachim Sauer
18834947038a7acb466855746df19d41ef26be507aa4Joachim Sauer        return bestMatch.matchLength() + start;
18844947038a7acb466855746df19d41ef26be507aa4Joachim Sauer    }
18854947038a7acb466855746df19d41ef26be507aa4Joachim Sauer
18864947038a7acb466855746df19d41ef26be507aa4Joachim Sauer    /**
18874947038a7acb466855746df19d41ef26be507aa4Joachim Sauer     * Parses the time zone string using the information in {@link #formatData}.
18884947038a7acb466855746df19d41ef26be507aa4Joachim Sauer     */
18894947038a7acb466855746df19d41ef26be507aa4Joachim Sauer    private int subParseZoneStringFromSymbols(String text, int start, CalendarBuilder calb) {
1890d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer        // END Android-changed: Parse time zone strings using ICU TimeZoneNames.
189151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        boolean useSameName = false; // true if standard and daylight time use the same abbreviation.
189251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        TimeZone currentTimeZone = getTimeZone();
189351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
189451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // At this point, check for named time zones by looking through
189551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // the locale data from the TimeZoneNames strings.
189651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // Want to be able to parse both short and long forms.
189751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int zoneIndex = formatData.getZoneIndex(currentTimeZone.getID());
189851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        TimeZone tz = null;
189951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        String[][] zoneStrings = formatData.getZoneStringsWrapper();
190051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        String[] zoneNames = null;
190151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int nameIndex = 0;
190251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (zoneIndex != -1) {
190351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            zoneNames = zoneStrings[zoneIndex];
190451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
190551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (nameIndex <= 2) {
190651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // Check if the standard name (abbr) and the daylight name are the same.
190751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
190851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
190951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                tz = TimeZone.getTimeZone(zoneNames[0]);
191051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
191151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
191251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (tz == null) {
191351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            zoneIndex = formatData.getZoneIndex(TimeZone.getDefault().getID());
191451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (zoneIndex != -1) {
191551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                zoneNames = zoneStrings[zoneIndex];
191651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
191751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (nameIndex <= 2) {
191851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
191951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
192051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    tz = TimeZone.getTimeZone(zoneNames[0]);
192151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
192251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
192351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
192451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
192551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (tz == null) {
192651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int len = zoneStrings.length;
192751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            for (int i = 0; i < len; i++) {
192851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                zoneNames = zoneStrings[i];
192951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
193051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (nameIndex <= 2) {
193151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
193251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
193351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    tz = TimeZone.getTimeZone(zoneNames[0]);
193451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    break;
193551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
193651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
193751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
193851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (tz != null) { // Matched any ?
193951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (!tz.equals(currentTimeZone)) {
194051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                setTimeZone(tz);
194151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
194251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // If the time zone matched uses the same name
194351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // (abbreviation) for both standard and daylight time,
194451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // let the time zone in the Calendar decide which one.
194551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            //
194651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // Also if tz.getDSTSaving() returns 0 for DST, use tz to
194751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // determine the local time. (6645292)
194851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int dstAmount = (nameIndex >= 3) ? tz.getDSTSavings() : 0;
194951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (!(useSameName || (nameIndex >= 3 && dstAmount == 0))) {
195051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                calb.clear(Calendar.ZONE_OFFSET).set(Calendar.DST_OFFSET, dstAmount);
195151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
195251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return (start + zoneNames[nameIndex].length());
195351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
1954242478c8a84d2fc9fd2e47f2b143622f1c9405dbJoachim Sauer        return -start;
195551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
195651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
195751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
195851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Parses numeric forms of time zone offset, such as "hh:mm", and
195951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * sets calb to the parsed value.
196051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
196151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param text  the text to be parsed
196251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param start the character position to start parsing
196351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param sign  1: positive; -1: negative
196451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param count 0: 'Z' or "GMT+hh:mm" parsing; 1 - 3: the number of 'X's
1965d06c9ff1e64308978a6db2135d744613e396b65eNarayan Kamath     * @param colonRequired true - colon required between hh and mm; false - no colon required
196651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param calb  a CalendarBuilder in which the parsed value is stored
196751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return updated parsed position, or its negative value to indicate a parsing error
196851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
196951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private int subParseNumericZone(String text, int start, int sign, int count,
1970d06c9ff1e64308978a6db2135d744613e396b65eNarayan Kamath                                    boolean colonRequired, CalendarBuilder calb) {
197151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int index = start;
197251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
197351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski      parse:
197451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        try {
197551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            char c = text.charAt(index++);
197651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // Parse hh
197751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int hours;
197851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (!isDigit(c)) {
197951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break parse;
198051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
198151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            hours = c - '0';
198251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            c = text.charAt(index++);
198351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (isDigit(c)) {
198451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                hours = hours * 10 + (c - '0');
198551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            } else {
198651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                --index;
198751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
198851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (hours > 23) {
198951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break parse;
199051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
199151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int minutes = 0;
199251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (count != 1) {
199351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // Proceed with parsing mm
199451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                c = text.charAt(index++);
1995d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer                // BEGIN Android-changed: Intentional change in behavior from OpenJDK.
1996d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer                // OpenJDK will return an error code if a : is found and colonRequired is false,
1997d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer                // this will return an error code if a : is not found and colonRequired is true.
1998af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                //
1999af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                // colonRequired | c == ':' | OpenJDK | this
2000af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                //   false       |  false   |   ok    |  ok
2001af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                //   false       |  true    |  error  |  ok
2002af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                //   true        |  false   |   ok    | error
2003af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin                //   true        |  true    |   ok    |  ok
2004d06c9ff1e64308978a6db2135d744613e396b65eNarayan Kamath                if (c == ':') {
200551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    c = text.charAt(index++);
2006d06c9ff1e64308978a6db2135d744613e396b65eNarayan Kamath                } else if (colonRequired) {
2007d06c9ff1e64308978a6db2135d744613e396b65eNarayan Kamath                    break parse;
200851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
2009d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer                // END Android-changed: Intentional change in behavior from OpenJDK.
201051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (!isDigit(c)) {
201151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    break parse;
201251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
201351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                minutes = c - '0';
201451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                c = text.charAt(index++);
201551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (!isDigit(c)) {
201651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    break parse;
201751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
201851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                minutes = minutes * 10 + (c - '0');
201951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (minutes > 59) {
202051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    break parse;
202151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
202251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
202351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            minutes += hours * 60;
202451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            calb.set(Calendar.ZONE_OFFSET, minutes * MILLIS_PER_MINUTE * sign)
202551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                .set(Calendar.DST_OFFSET, 0);
202651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return index;
202751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } catch (IndexOutOfBoundsException e) {
202851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
202951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return  1 - index; // -(index - 1)
203051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
203151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
203251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private boolean isDigit(char c) {
203351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return c >= '0' && c <= '9';
203451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
203551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
203651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
203751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Private member function that converts the parsed date strings into
203851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * timeFields. Returns -start (for ParsePosition) if failed.
203951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param text the time text to be parsed.
204051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param start where to start parsing.
20416e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin     * @param patternCharIndex the index of the pattern character.
204251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param count the count of a pattern character.
204351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param obeyCount if true, then the next field directly abuts this one,
204451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * and we should use the count to know when to stop parsing.
204551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param ambiguousYear return parameter; upon return, if ambiguousYear[0]
204651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * is true, then a two-digit year was parsed and may need to be readjusted.
204751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param origPos origPos.errorIndex is used to return an error index
204851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * at which a parse error occurred, if matching failure occurs.
204951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the new start position if matching succeeded; -1 indicating
205051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * matching failure, otherwise. In case matching failure occurred,
205151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * an error index is set to origPos.errorIndex.
205251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
205351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private int subParse(String text, int start, int patternCharIndex, int count,
205451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                         boolean obeyCount, boolean[] ambiguousYear,
205551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                         ParsePosition origPos,
205651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                         boolean useFollowingMinusSignAsDelimiter, CalendarBuilder calb) {
20576e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        Number number;
205851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int value = 0;
205951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        ParsePosition pos = new ParsePosition(0);
206051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        pos.index = start;
206151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (patternCharIndex == PATTERN_WEEK_YEAR && !calendar.isWeekDateSupported()) {
206251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // use calendar year 'y' instead
206351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            patternCharIndex = PATTERN_YEAR;
206451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
206551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
206651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
206751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // If there are any spaces here, skip over them.  If we hit the end
206851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // of the string, then fail.
206951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (;;) {
207051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (pos.index >= text.length()) {
207151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                origPos.errorIndex = start;
207251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return -1;
207351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
207451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            char c = text.charAt(pos.index);
20756e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin            if (c != ' ' && c != '\t') {
20766e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                break;
20776e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin            }
207851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            ++pos.index;
207951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
208051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
208151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski      parsing:
208251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        {
208351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // We handle a few special cases here where we need to parse
208451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // a number value.  We handle further, more generic cases below.  We need
208551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // to handle some of them here because some fields require extra processing on
208651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // the parsed value.
208751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (patternCharIndex == PATTERN_HOUR_OF_DAY1 ||
208851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                patternCharIndex == PATTERN_HOUR1 ||
208951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                (patternCharIndex == PATTERN_MONTH && count <= 2) ||
209051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                patternCharIndex == PATTERN_YEAR ||
209151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                patternCharIndex == PATTERN_WEEK_YEAR) {
209251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // It would be good to unify this with the obeyCount logic below,
209351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // but that's going to be difficult.
209451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (obeyCount) {
209551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if ((start+count) > text.length()) {
209651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        break parsing;
209751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
209851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    number = numberFormat.parse(text.substring(0, start+count), pos);
209951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                } else {
210051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    number = numberFormat.parse(text, pos);
210151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
210251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (number == null) {
210351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (patternCharIndex != PATTERN_YEAR || calendar instanceof GregorianCalendar) {
210451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        break parsing;
210551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
210651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                } else {
210751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    value = number.intValue();
210851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
210951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (useFollowingMinusSignAsDelimiter && (value < 0) &&
211051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        (((pos.index < text.length()) &&
211151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                         (text.charAt(pos.index) != minusSign)) ||
211251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                         ((pos.index == text.length()) &&
211351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                          (text.charAt(pos.index-1) == minusSign)))) {
211451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        value = -value;
211551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        pos.index--;
211651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
211751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
211851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
211951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
212051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            boolean useDateFormatSymbols = useDateFormatSymbols();
212151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
212251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int index;
212351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            switch (patternCharIndex) {
212451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            case PATTERN_ERA: // 'G'
212551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (useDateFormatSymbols) {
212651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if ((index = matchString(text, start, Calendar.ERA, formatData.getEras(), calb)) > 0) {
212751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        return index;
212851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
212951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                } else {
213051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    Map<String, Integer> map = calendar.getDisplayNames(field,
213151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                                        Calendar.ALL_STYLES,
213251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                                        locale);
213351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if ((index = matchString(text, start, field, map, calb)) > 0) {
213451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        return index;
213551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
213651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
213751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break parsing;
213851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
213951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            case PATTERN_WEEK_YEAR: // 'Y'
214051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            case PATTERN_YEAR:      // 'y'
214151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (!(calendar instanceof GregorianCalendar)) {
214251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // calendar might have text representations for year values,
214351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // such as "\u5143" in JapaneseImperialCalendar.
214451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    int style = (count >= 4) ? Calendar.LONG : Calendar.SHORT;
214551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    Map<String, Integer> map = calendar.getDisplayNames(field, style, locale);
214651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (map != null) {
214751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        if ((index = matchString(text, start, field, map, calb)) > 0) {
214851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            return index;
214951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        }
215051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
215151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    calb.set(field, value);
215251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return pos.index;
215351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
215451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
215551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // If there are 3 or more YEAR pattern characters, this indicates
215651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // that the year value is to be treated literally, without any
215751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // two-digit year adjustments (e.g., from "01" to 2001).  Otherwise
215851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // we made adjustments to place the 2-digit year in the proper
215951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // century, for parsed strings from "00" to "99".  Any other string
216051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // is treated literally:  "2250", "-1", "1", "002".
216151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (count <= 2 && (pos.index - start) == 2
216251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    && Character.isDigit(text.charAt(start))
216351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    && Character.isDigit(text.charAt(start+1))) {
216451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // Assume for example that the defaultCenturyStart is 6/18/1903.
216551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // This means that two-digit years will be forced into the range
216651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // 6/18/1903 to 6/17/2003.  As a result, years 00, 01, and 02
216751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // correspond to 2000, 2001, and 2002.  Years 04, 05, etc. correspond
216851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // to 1904, 1905, etc.  If the year is 03, then it is 2003 if the
216951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // other fields specify a date before 6/18, or 1903 if they specify a
217051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // date afterwards.  As a result, 03 is an ambiguous year.  All other
217151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // two-digit years are unambiguous.
217251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    int ambiguousTwoDigitYear = defaultCenturyStartYear % 100;
217351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    ambiguousYear[0] = value == ambiguousTwoDigitYear;
217451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    value += (defaultCenturyStartYear/100)*100 +
217551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        (value < ambiguousTwoDigitYear ? 100 : 0);
217651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
217751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                calb.set(field, value);
217851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return pos.index;
217951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
21804c8d6d2a84cffba9a34ea03d534d77027fb1974ePaul Duffin            case PATTERN_MONTH: // 'M'
2181d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer            // BEGIN Android-changed: extract parseMonth method.
2182d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            {
2183d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                final int idx = parseMonth(text, count, value, start, field, pos,
21844c8d6d2a84cffba9a34ea03d534d77027fb1974ePaul Duffin                        useDateFormatSymbols, false /* isStandalone */, calb);
2185d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                if (idx > 0) {
2186d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    return idx;
218751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
21884c8d6d2a84cffba9a34ea03d534d77027fb1974ePaul Duffin
2189d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                break parsing;
2190d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            }
219151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2192af18bc9973eca35fc0d4db6e240323f38c9d7a91Paul Duffin            case PATTERN_MONTH_STANDALONE: // 'L'.
2193d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            {
2194d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                final int idx = parseMonth(text, count, value, start, field, pos,
21954c8d6d2a84cffba9a34ea03d534d77027fb1974ePaul Duffin                        useDateFormatSymbols, true /* isStandalone */, calb);
2196d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                if (idx > 0) {
2197d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    return idx;
219851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
219951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break parsing;
2200d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            }
2201d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer            // END Android-changed: extract parseMonth method.
220251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
220351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            case PATTERN_HOUR_OF_DAY1: // 'k' 1-based.  eg, 23:59 + 1 hour =>> 24:59
220451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (!isLenient()) {
220551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // Validate the hour value in non-lenient
220651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (value < 1 || value > 24) {
220751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        break parsing;
220851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
220951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
221051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // [We computed 'value' above.]
22116e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                if (value == calendar.getMaximum(Calendar.HOUR_OF_DAY) + 1) {
221251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    value = 0;
22136e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                }
221451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                calb.set(Calendar.HOUR_OF_DAY, value);
221551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return pos.index;
221651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
22174c8d6d2a84cffba9a34ea03d534d77027fb1974ePaul Duffin            case PATTERN_DAY_OF_WEEK:  // 'E'
2218d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer            // BEGIN Android-changed: extract parseWeekday method.
2219d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            {
2220d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                final int idx = parseWeekday(text, start, field, useDateFormatSymbols,
2221d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                        false /* standalone */, calb);
2222d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                if (idx > 0) {
2223d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    return idx;
2224d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                }
2225d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                break parsing;
2226d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            }
2227d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer            // END Android-changed: extract parseWeekday method.
2228d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
2229d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer            // BEGIN Android-added: support for 'c' (standalone day of week).
22304c8d6d2a84cffba9a34ea03d534d77027fb1974ePaul Duffin            case PATTERN_STANDALONE_DAY_OF_WEEK: // 'c'
2231d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            {
2232d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                final int idx = parseWeekday(text, start, field, useDateFormatSymbols,
223391116215bcb3e903fc334eaf23898b0d8ece6924Joachim Sauer                        true /* standalone */, calb);
2234d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                if (idx > 0) {
2235d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    return idx;
223651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
2237d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
223851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break parsing;
2239d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            }
2240d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer            // END Android-added: support for 'c' (standalone day of week).
2241d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
224251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            case PATTERN_AM_PM:    // 'a'
224351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (useDateFormatSymbols) {
224451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if ((index = matchString(text, start, Calendar.AM_PM,
224551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                             formatData.getAmPmStrings(), calb)) > 0) {
224651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        return index;
224751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
224851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                } else {
224951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    Map<String,Integer> map = calendar.getDisplayNames(field, Calendar.ALL_STYLES, locale);
225051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if ((index = matchString(text, start, field, map, calb)) > 0) {
225151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        return index;
225251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
225351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
225451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break parsing;
225551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
225651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            case PATTERN_HOUR1: // 'h' 1-based.  eg, 11PM + 1 hour =>> 12 AM
225751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (!isLenient()) {
225851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // Validate the hour value in non-lenient
225951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (value < 1 || value > 12) {
226051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        break parsing;
226151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
226251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
226351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // [We computed 'value' above.]
22646e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                if (value == calendar.getLeastMaximum(Calendar.HOUR) + 1) {
226551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    value = 0;
22666e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                }
226751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                calb.set(Calendar.HOUR, value);
226851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return pos.index;
226951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
227051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            case PATTERN_ZONE_NAME:  // 'z'
227151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            case PATTERN_ZONE_VALUE: // 'Z'
227251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                {
227351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    int sign = 0;
227451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    try {
227551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        char c = text.charAt(pos.index);
227651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        if (c == '+') {
227751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            sign = 1;
227851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        } else if (c == '-') {
227951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            sign = -1;
228051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        }
228151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        if (sign == 0) {
228251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            // Try parsing a custom time zone "GMT+hh:mm" or "GMT".
228351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            if ((c == 'G' || c == 'g')
228451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                && (text.length() - start) >= GMT.length()
228551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                && text.regionMatches(true, start, GMT, 0, GMT.length())) {
228651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                pos.index = start + GMT.length();
228751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
228851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                if ((text.length() - pos.index) > 0) {
228951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                    c = text.charAt(pos.index);
229051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                    if (c == '+') {
229151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                        sign = 1;
229251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                    } else if (c == '-') {
229351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                        sign = -1;
229451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                    }
229551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                }
229651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
229751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                if (sign == 0) {    /* "GMT" without offset */
229851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                    calb.set(Calendar.ZONE_OFFSET, 0)
229951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                        .set(Calendar.DST_OFFSET, 0);
230051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                    return pos.index;
230151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                }
2302d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer                                // Android-changed: tolerate colon in zone offset.
2303d06c9ff1e64308978a6db2135d744613e396b65eNarayan Kamath                                // Parse the rest as "hh[:]?mm"
2304d06c9ff1e64308978a6db2135d744613e396b65eNarayan Kamath                                int i = subParseNumericZone(text, ++pos.index, sign, 0,
2305d06c9ff1e64308978a6db2135d744613e396b65eNarayan Kamath                                        false, calb);
230651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                if (i > 0) {
230751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                    return i;
230851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                }
230951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                pos.index = -i;
231051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            } else {
231151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                // Try parsing the text as a time zone
231251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                // name or abbreviation.
231351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                int i = subParseZoneString(text, pos.index, calb);
231451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                if (i > 0) {
231551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                    return i;
231651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                }
231751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                pos.index = -i;
231851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            }
231951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        } else {
2320d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer                            // Android-changed: tolerate colon in zone offset.
2321d06c9ff1e64308978a6db2135d744613e396b65eNarayan Kamath                            // Parse the rest as "hh[:]?mm" (RFC 822)
2322d06c9ff1e64308978a6db2135d744613e396b65eNarayan Kamath                            int i = subParseNumericZone(text, ++pos.index, sign, 0,
2323d06c9ff1e64308978a6db2135d744613e396b65eNarayan Kamath                                    false, calb);
232451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            if (i > 0) {
232551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                return i;
232651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            }
232751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            pos.index = -i;
232851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        }
232951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    } catch (IndexOutOfBoundsException e) {
233051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
233151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
233251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break parsing;
233351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
233451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            case PATTERN_ISO_ZONE:   // 'X'
233551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                {
233651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if ((text.length() - pos.index) <= 0) {
233751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        break parsing;
233851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
233951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
23406e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                    int sign;
234151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    char c = text.charAt(pos.index);
234251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (c == 'Z') {
234351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        calb.set(Calendar.ZONE_OFFSET, 0).set(Calendar.DST_OFFSET, 0);
234451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        return ++pos.index;
234551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
234651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
234751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // parse text as "+/-hh[[:]mm]" based on count
234851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (c == '+') {
234951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        sign = 1;
235051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    } else if (c == '-') {
235151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        sign = -1;
235251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    } else {
235351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        ++pos.index;
235451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        break parsing;
235551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
23566e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                    int i = subParseNumericZone(text, ++pos.index, sign, count,
23576e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                                                count == 3, calb);
235851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (i > 0) {
235951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        return i;
236051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
236151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    pos.index = -i;
236251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
236351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break parsing;
236451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
236551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            default:
236651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         // case PATTERN_DAY_OF_MONTH:         // 'd'
236751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         // case PATTERN_HOUR_OF_DAY0:         // 'H' 0-based.  eg, 23:59 + 1 hour =>> 00:59
236851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         // case PATTERN_MINUTE:               // 'm'
236951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         // case PATTERN_SECOND:               // 's'
237051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         // case PATTERN_MILLISECOND:          // 'S'
237151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         // case PATTERN_DAY_OF_YEAR:          // 'D'
237251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         // case PATTERN_DAY_OF_WEEK_IN_MONTH: // 'F'
237351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         // case PATTERN_WEEK_OF_YEAR:         // 'w'
237451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         // case PATTERN_WEEK_OF_MONTH:        // 'W'
237551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         // case PATTERN_HOUR0:                // 'K' 0-based.  eg, 11PM + 1 hour =>> 0 AM
237651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         // case PATTERN_ISO_DAY_OF_WEEK:      // 'u' (pseudo field);
237751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
237851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // Handle "generic" fields
2379afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath                int parseStart = pos.getIndex();
238051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (obeyCount) {
238151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if ((start+count) > text.length()) {
238251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        break parsing;
238351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
238451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    number = numberFormat.parse(text.substring(0, start+count), pos);
238551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                } else {
238651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    number = numberFormat.parse(text, pos);
238751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
238851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (number != null) {
2389d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer                    // BEGIN Android-changed: Better UTS#35 conformity for fractional seconds.
2390afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath                    if (patternCharIndex == PATTERN_MILLISECOND) {
2391afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath                        // Fractional seconds must be treated specially. We must always
2392afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath                        // normalize them to their fractional second value [0, 1) before we attempt
2393afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath                        // to parse them.
2394afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath                        //
2395afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath                        // Case 1: 11.78 seconds is 11 seconds and 780 (not 78) milliseconds.
2396afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath                        // Case 2: 11.7890567 seconds is 11 seconds and 789 (not 7890567) milliseconds.
2397afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath                        double doubleValue = number.doubleValue();
2398afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath                        int width = pos.getIndex() - parseStart;
2399afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath                        final double divisor = Math.pow(10, width);
2400afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath                        value = (int) ((doubleValue / divisor) * 1000);
2401afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath                    } else {
2402afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath                        value = number.intValue();
2403afe86efb5d4b237c50df82b7dcb581d4d75b1132Narayan Kamath                    }
2404d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer                    // END Android-changed: Better UTS#35 conformity for fractional seconds.
240551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
240651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (useFollowingMinusSignAsDelimiter && (value < 0) &&
24074c8d6d2a84cffba9a34ea03d534d77027fb1974ePaul Duffin                        (((pos.index < text.length()) &&
24084c8d6d2a84cffba9a34ea03d534d77027fb1974ePaul Duffin                         (text.charAt(pos.index) != minusSign)) ||
24094c8d6d2a84cffba9a34ea03d534d77027fb1974ePaul Duffin                         ((pos.index == text.length()) &&
24104c8d6d2a84cffba9a34ea03d534d77027fb1974ePaul Duffin                          (text.charAt(pos.index-1) == minusSign)))) {
241151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        value = -value;
241251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        pos.index--;
241351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
241451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
241551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    calb.set(field, value);
241651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return pos.index;
241751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
241851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                break parsing;
241951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
242051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
242151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
242251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // Parsing failed.
242351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        origPos.errorIndex = pos.index;
242451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return -1;
242551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
242651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2427d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer    // BEGIN Android-added: parseMonth and parseWeekday methods to parse using ICU data.
2428d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath    private int parseMonth(String text, int count, int value, int start,
2429d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                           int field, ParsePosition pos, boolean useDateFormatSymbols,
2430d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                           boolean standalone,
2431d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                           CalendarBuilder out) {
2432d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        if (count <= 2) // i.e., M or MM.
2433d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        {
2434d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            // Don't want to parse the month if it is a string
2435d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            // while pattern uses numeric style: M or MM.
2436d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            // [We computed 'value' above.]
2437d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            out.set(Calendar.MONTH, value - 1);
2438d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            return pos.index;
2439d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        }
2440d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
2441d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        int index = -1;
2442d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        if (useDateFormatSymbols) {
2443d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            // count >= 3 // i.e., MMM or MMMM
2444d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            // Want to be able to parse both short and long forms.
2445d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            // Try count == 4 first:
2446d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            if ((index = matchString(
2447d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    text, start, Calendar.MONTH,
2448d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    standalone ? formatData.getStandAloneMonths() : formatData.getMonths(),
2449d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    out)) > 0) {
2450d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                return index;
2451d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            }
2452d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            // count == 4 failed, now try count == 3
2453d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            if ((index = matchString(
2454d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    text, start, Calendar.MONTH,
2455d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    standalone ? formatData.getShortStandAloneMonths() : formatData.getShortMonths(),
2456d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    out)) > 0) {
2457d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                return index;
2458d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            }
2459d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        } else {
2460d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            Map<String, Integer> map = calendar.getDisplayNames(field,
2461d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    Calendar.ALL_STYLES,
2462d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    locale);
2463d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            if ((index = matchString(text, start, field, map, out)) > 0) {
2464d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                return index;
2465d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            }
2466d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        }
2467d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
2468d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        return index;
2469d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath    }
2470d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
2471d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath    private int parseWeekday(String text, int start, int field, boolean useDateFormatSymbols,
2472d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                             boolean standalone, CalendarBuilder out) {
2473d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        int index = -1;
2474d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        if (useDateFormatSymbols) {
2475d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            // Want to be able to parse both short and long forms.
2476d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            // Try count == 4 (DDDD) first:
2477d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            if ((index=matchString(
2478d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    text, start, Calendar.DAY_OF_WEEK,
2479d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    standalone ? formatData.getStandAloneWeekdays() : formatData.getWeekdays(),
2480d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    out)) > 0) {
2481d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                return index;
2482d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            }
2483d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
2484d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            // DDDD failed, now try DDD
2485d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            if ((index = matchString(
2486d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    text, start, Calendar.DAY_OF_WEEK,
2487d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    standalone ? formatData.getShortStandAloneWeekdays() : formatData.getShortWeekdays(),
2488d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    out)) > 0) {
2489d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                return index;
2490d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            }
2491d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        } else {
2492d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            int[] styles = { Calendar.LONG, Calendar.SHORT };
2493d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            for (int style : styles) {
2494d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                Map<String,Integer> map = calendar.getDisplayNames(field, style, locale);
2495d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                if ((index = matchString(text, start, field, map, out)) > 0) {
2496d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                    return index;
2497d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath                }
2498d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath            }
2499d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        }
2500d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
2501d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath        return index;
2502d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath    }
2503d7c6839b0afae1fc8ad25d8495aac3b34daf12ddJoachim Sauer    // END Android-added: parseMonth and parseWeekday methods to parse using ICU data.
2504d6c54ba7af74286d2e310703a4aa2c924ec85c99Narayan Kamath
250551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private final String getCalendarName() {
250651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return calendar.getClass().getName();
250751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
250851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
250951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private boolean useDateFormatSymbols() {
251051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (useDateFormatSymbols) {
251151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return true;
251251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
251351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return isGregorianCalendar() || locale == null;
251451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
251551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
251651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private boolean isGregorianCalendar() {
251751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return "java.util.GregorianCalendar".equals(getCalendarName());
251851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
251951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
252051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
252151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Translates a pattern, mapping each character in the from string to the
252251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * corresponding character in the to string.
252351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
252451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception IllegalArgumentException if the given pattern is invalid
252551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
252651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private String translatePattern(String pattern, String from, String to) {
252751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        StringBuilder result = new StringBuilder();
252851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        boolean inQuote = false;
252951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = 0; i < pattern.length(); ++i) {
253051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            char c = pattern.charAt(i);
253151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (inQuote) {
25326e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                if (c == '\'') {
253351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    inQuote = false;
25346e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                }
253551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
253651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            else {
25376e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                if (c == '\'') {
253851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    inQuote = true;
25396e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin                } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
254051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    int ci = from.indexOf(c);
254151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (ci >= 0) {
254251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        // patternChars is longer than localPatternChars due
254351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        // to serialization compatibility. The pattern letters
254451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        // unsupported by localPatternChars pass through.
254551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        if (ci < to.length()) {
254651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            c = to.charAt(ci);
254751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        }
254851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    } else {
254951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        throw new IllegalArgumentException("Illegal pattern " +
255051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                           " character '" +
255151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                           c + "'");
255251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
255351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
255451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
255551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            result.append(c);
255651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
25576e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        if (inQuote) {
255851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new IllegalArgumentException("Unfinished quote in pattern");
25596e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        }
256051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return result.toString();
256151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
256251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
256351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
256451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns a pattern string describing this date format.
256551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
256651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return a pattern string describing this date format.
256751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
256851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String toPattern() {
256951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return pattern;
257051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
257151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
257251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
257351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns a localized pattern string describing this date format.
257451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
257551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return a localized pattern string describing this date format.
257651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
257751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String toLocalizedPattern() {
257851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return translatePattern(pattern,
257951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                DateFormatSymbols.patternChars,
258051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                formatData.getLocalPatternChars());
258151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
258251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
258351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
258451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Applies the given pattern string to this date format.
258551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
258651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param pattern the new date and time pattern for this date format
258751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception NullPointerException if the given pattern is null
258851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception IllegalArgumentException if the given pattern is invalid
258951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
259051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void applyPattern(String pattern)
259151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
259251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        compiledPattern = compile(pattern);
259351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.pattern = pattern;
259451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
259551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
259651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
259751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Applies the given localized pattern string to this date format.
259851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
259951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param pattern a String to be mapped to the new date and time format
260051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *        pattern for this format
260151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception NullPointerException if the given pattern is null
260251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception IllegalArgumentException if the given pattern is invalid
260351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
260451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void applyLocalizedPattern(String pattern) {
260551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         String p = translatePattern(pattern,
260651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                     formatData.getLocalPatternChars(),
260751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                     DateFormatSymbols.patternChars);
260851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         compiledPattern = compile(p);
260951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski         this.pattern = p;
261051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
261151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
261251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
261351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Gets a copy of the date and time format symbols of this date format.
261451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
261551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the date and time format symbols of this date format
261651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @see #setDateFormatSymbols
261751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
261851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public DateFormatSymbols getDateFormatSymbols()
261951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
262051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return (DateFormatSymbols)formatData.clone();
262151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
262251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
262351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
262451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Sets the date and time format symbols of this date format.
262551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
262651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @param newFormatSymbols the new date and time format symbols
262751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception NullPointerException if the given newFormatSymbols is null
262851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @see #getDateFormatSymbols
262951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
263051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void setDateFormatSymbols(DateFormatSymbols newFormatSymbols)
263151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
263251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.formatData = (DateFormatSymbols)newFormatSymbols.clone();
263351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        useDateFormatSymbols = true;
263451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
263551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
263651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
263751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Creates a copy of this <code>SimpleDateFormat</code>. This also
263851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * clones the format's date format symbols.
263951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
264051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return a clone of this <code>SimpleDateFormat</code>
264151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
26426e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin    @Override
264351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public Object clone() {
264451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        SimpleDateFormat other = (SimpleDateFormat) super.clone();
264551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        other.formatData = (DateFormatSymbols) formatData.clone();
264651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return other;
264751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
264851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
264951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
265051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Returns the hash code value for this <code>SimpleDateFormat</code> object.
265151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
265251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return the hash code value for this <code>SimpleDateFormat</code> object.
265351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
26546e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin    @Override
265551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int hashCode()
265651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
265751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return pattern.hashCode();
265851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // just enough fields for a reasonable distribution
265951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
266051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
266151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
266251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Compares the given object with this <code>SimpleDateFormat</code> for
266351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * equality.
266451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
266551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return true if the given object is equal to this
266651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <code>SimpleDateFormat</code>
266751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
26686e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin    @Override
266951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public boolean equals(Object obj)
267051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
26716e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        if (!super.equals(obj)) {
26726e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin            return false; // super does class check
26736e42190c7f7d7cf3d8b787c918de0d797c6ddbbaPaul Duffin        }
267451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        SimpleDateFormat that = (SimpleDateFormat) obj;
267551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return (pattern.equals(that.pattern)
267651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                && formatData.equals(that.formatData));
267751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
267851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
267951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
268051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * After reading an object from the input stream, the format
268151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * pattern in the object is verified.
268251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <p>
268351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @exception InvalidObjectException if the pattern is invalid
268451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
268551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void readObject(ObjectInputStream stream)
268651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                         throws IOException, ClassNotFoundException {
268751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        stream.defaultReadObject();
268851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
268951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        try {
269051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            compiledPattern = compile(pattern);
269151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } catch (Exception e) {
269251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            throw new InvalidObjectException("invalid pattern");
269351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
269451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
269551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (serialVersionOnStream < 1) {
269651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // didn't have defaultCenturyStart field
269751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            initializeDefaultCentury();
269851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
269951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        else {
270051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // fill in dependent transient field
270151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            parseAmbiguousDatesAsAfter(defaultCenturyStart);
270251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
270351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        serialVersionOnStream = currentSerialVersion;
270451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
270551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // If the deserialized object has a SimpleTimeZone, try
270651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // to replace it with a ZoneInfo equivalent in order to
270751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // be compatible with the SimpleTimeZone-based
270851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // implementation as much as possible.
270951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        TimeZone tz = getTimeZone();
271051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (tz instanceof SimpleTimeZone) {
271151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            String id = tz.getID();
271251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            TimeZone zi = TimeZone.getTimeZone(id);
271351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (zi != null && zi.hasSameRules(tz) && zi.getID().equals(id)) {
271451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                setTimeZone(zi);
271551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
271651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
271751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
271851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
271951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
272051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Analyze the negative subpattern of DecimalFormat and set/update values
272151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * as necessary.
272251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
272351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void checkNegativeNumberExpression() {
272451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if ((numberFormat instanceof DecimalFormat) &&
272551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            !numberFormat.equals(originalNumberFormat)) {
272651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            String numberPattern = ((DecimalFormat)numberFormat).toPattern();
272751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (!numberPattern.equals(originalNumberPattern)) {
272851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                hasFollowingMinusSign = false;
272951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
273051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                int separatorIndex = numberPattern.indexOf(';');
273151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // If the negative subpattern is not absent, we have to analayze
273251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // it in order to check if it has a following minus sign.
273351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (separatorIndex > -1) {
273451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    int minusIndex = numberPattern.indexOf('-', separatorIndex);
273551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if ((minusIndex > numberPattern.lastIndexOf('0')) &&
273651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        (minusIndex > numberPattern.lastIndexOf('#'))) {
273751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        hasFollowingMinusSign = true;
273851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        minusSign = ((DecimalFormat)numberFormat).getDecimalFormatSymbols().getMinusSign();
273951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
274051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
274151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                originalNumberPattern = numberPattern;
274251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
274351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            originalNumberFormat = numberFormat;
274451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
274551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
274651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
274751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
2748