12ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* GENERATED SOURCE. DO NOT MODIFY. */
22ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*
32ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller*   Copyright (C) 2008-2015, International Business Machines
42ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller*   Corporation and others.  All Rights Reserved.
52ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller*/
62ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
72ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpackage android.icu.text;
82ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
92ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.io.IOException;
102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.io.ObjectInputStream;
112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.text.FieldPosition;
122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.text.ParsePosition;
132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Collections;
142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.HashMap;
152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Locale;
162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Map;
172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.CalendarData;
192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.ICUCache;
202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.SimpleCache;
212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.text.DateIntervalInfo.PatternInfo;
222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.Calendar;
232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.DateInterval;
242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.Output;
252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.TimeZone;
262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.ULocale;
272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.ULocale.Category;
282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/**
312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * DateIntervalFormat is a class for formatting and parsing date
322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * intervals in a language-independent manner.
332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Only formatting is supported. Parsing is not supported.
342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P>
362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Date interval means from one date to another date,
372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * for example, from "Jan 11, 2008" to "Jan 18, 2008".
382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * We introduced class DateInterval to represent it.
392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * DateInterval is a pair of UDate, which is
402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the standard milliseconds since 24:00 GMT, Jan 1, 1970.
412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P>
432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * DateIntervalFormat formats a DateInterval into
442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * text as compactly as possible.
452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For example, the date interval format from "Jan 11, 2008" to "Jan 18,. 2008"
462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * is "Jan 11-18, 2008" for English.
472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * And it parses text into DateInterval,
482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * although initially, parsing is not supported.
492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P>
512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * There is no structural information in date time patterns.
522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For any punctuations and string literals inside a date time pattern,
532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * we do not know whether it is just a separator, or a prefix, or a suffix.
542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Without such information, so, it is difficult to generate a sub-pattern
552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * (or super-pattern) by algorithm.
562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * So, formatting a DateInterval is pattern-driven. It is very
572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * similar to formatting in SimpleDateFormat.
582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * We introduce class DateIntervalInfo to save date interval
592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * patterns, similar to date time pattern in SimpleDateFormat.
602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P>
622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Logically, the interval patterns are mappings
632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * from (skeleton, the_largest_different_calendar_field)
642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * to (date_interval_pattern).
652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P>
672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * A skeleton
682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <ol>
692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>
702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * only keeps the field pattern letter and ignores all other parts
712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * in a pattern, such as space, punctuations, and string literals.
722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>
732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * hides the order of fields.
742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>
752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * might hide a field's pattern letter length.
762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For those non-digit calendar fields, the pattern letter length is
782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * important, such as MMM, MMMM, and MMMMM; EEE and EEEE,
792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and the field's pattern letter length is honored.
802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For the digit calendar fields,  such as M or MM, d or dd, yy or yyyy,
822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the field pattern length is ignored and the best match, which is defined
832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * in date time patterns, will be returned without honor the field pattern
842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * letter length in skeleton.
852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </ol>
862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P>
882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The calendar fields we support for interval formatting are:
892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * year, month, date, day-of-week, am-pm, hour, hour-of-day, minute, and
902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * second (though we do not currently have specific intervalFormat data for
912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * skeletons with seconds).
922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Those calendar fields can be defined in the following order:
93bfab1e7fec36dff93fb980c546ad64a565faf9fcPaul Duffin * year &gt; month &gt; date &gt; hour (in day) &gt; minute &gt; second
942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The largest different calendar fields between 2 calendars is the
962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * first different calendar field in above order.
972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For example: the largest different calendar fields between "Jan 10, 2007"
992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and "Feb 20, 2008" is year.
1002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P>
1022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For other calendar fields, the compact interval formatting is not
1032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * supported. And the interval format will be fall back to fall-back
1042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * patterns, which is mostly "{date0} - {date1}".
1052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P>
1072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * There is a set of pre-defined static skeleton strings in DateFormat,
1082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * There are pre-defined interval patterns for those pre-defined skeletons
1092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * in locales' resource files.
1102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For example, for a skeleton YEAR_ABBR_MONTH_DAY, which is  "yMMMd",
1112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * in  en_US, if the largest different calendar field between date1 and date2
1122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * is "year", the date interval pattern  is "MMM d, yyyy - MMM d, yyyy",
1132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * such as "Jan 10, 2007 - Jan 10, 2008".
1142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If the largest different calendar field between date1 and date2 is "month",
1152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the date interval pattern is "MMM d - MMM d, yyyy",
1162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * such as "Jan 10 - Feb 10, 2007".
1172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If the largest different calendar field between date1 and date2 is "day",
1182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the date interval pattern is ""MMM d-d, yyyy", such as "Jan 10-20, 2007".
1192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For date skeleton, the interval patterns when year, or month, or date is
1212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * different are defined in resource files.
1222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For time skeleton, the interval patterns when am/pm, or hour, or minute is
1232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * different are defined in resource files.
1242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P>
1262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If a skeleton is not found in a locale's DateIntervalInfo, which means
1272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the interval patterns for the skeleton is not defined in resource file,
1282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the interval pattern will falls back to the interval "fallback" pattern
1292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * defined in resource file.
1302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If the interval "fallback" pattern is not defined, the default fall-back
1312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * is "{date0} - {data1}".
1322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P>
1342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For the combination of date and time,
1352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The rule to genearte interval patterns are:
1362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <ol>
1372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>
1382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    when the year, month, or day differs, falls back to fall-back
1392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    interval pattern, which mostly is the concatenate the two original
1402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    expressions with a separator between,
1412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    For example, interval pattern from "Jan 10, 2007 10:10 am"
1422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    to "Jan 11, 2007 10:10am" is
1432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    "Jan 10, 2007 10:10 am - Jan 11, 2007 10:10am"
1442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>
1452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    otherwise, present the date followed by the range expression
1462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    for the time.
1472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    For example, interval pattern from "Jan 10, 2007 10:10 am"
1482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    to "Jan 10, 2007 11:10am" is "Jan 10, 2007 10:10 am - 11:10am"
1492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </ol>
1502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P>
1532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If two dates are the same, the interval pattern is the single date pattern.
1542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For example, interval pattern from "Jan 10, 2007" to "Jan 10, 2007" is
1552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * "Jan 10, 2007".
1562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Or if the presenting fields between 2 dates have the exact same values,
1582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the interval pattern is the  single date pattern.
1592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For example, if user only requests year and month,
1602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the interval pattern from "Jan 10, 2007" to "Jan 20, 2007" is "Jan 2007".
1612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P>
1632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * DateIntervalFormat needs the following information for correct
1642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * formatting: time zone, calendar type, pattern, date format symbols,
1652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and date interval patterns.
1662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * It can be instantiated in several ways:
1672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <ol>
1682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>
1692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    create an instance using default or given locale plus given skeleton.
1702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    Users are encouraged to created date interval formatter this way and
1712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    to use the pre-defined skeleton macros, such as
1722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    YEAR_NUM_MONTH, which consists the calendar fields and
1732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    the format style.
1742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </li>
1752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li>
1762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    create an instance using default or given locale plus given skeleton
1772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    plus a given DateIntervalInfo.
1782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    This factory method is for powerful users who want to provide their own
1792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    interval patterns.
1802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    Locale provides the timezone, calendar, and format symbols information.
1812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    Local plus skeleton provides full pattern information.
1822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *    DateIntervalInfo provides the date interval patterns.
1832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </li>
1842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </ol>
1852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P>
1872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For the calendar field pattern letter, such as G, y, M, d, a, h, H, m, s etc.
1882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * DateIntervalFormat uses the same syntax as that of
1892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * DateTime format.
1902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P>
1922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Code Sample: general usage
1932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <pre>
1942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
1952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   // the date interval object which the DateIntervalFormat formats on
1962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   // and parses into
1972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   DateInterval dtInterval = new DateInterval(1000*3600*24L, 1000*3600*24*2L);
1982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   DateIntervalFormat dtIntervalFmt = DateIntervalFormat.getInstance(
1992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *                   YEAR_MONTH_DAY, Locale("en", "GB", ""));
2002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   StringBuffer str = new StringBuffer("");
2012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   FieldPosition pos = new FieldPosition(0);
2022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   // formatting
2032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *   dtIntervalFmt.format(dtInterval, dateIntervalString, pos);
2042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </pre>
2062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P>
2082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Code Sample: for powerful users who wants to use their own interval pattern
2092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <pre>
2102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2111fba789ac68efdd9120a7373f49daef42833e674Neil Fuller *     import android.icu.text.DateIntervalInfo;
2121fba789ac68efdd9120a7373f49daef42833e674Neil Fuller *     import android.icu.text.DateIntervalFormat;
2132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     ....................
2142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     // Get DateIntervalFormat instance using default locale
2162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     DateIntervalFormat dtitvfmt = DateIntervalFormat.getInstance(YEAR_MONTH_DAY);
2172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     // Create an empty DateIntervalInfo object, which does not have any interval patterns inside.
2192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     dtitvinf = new DateIntervalInfo();
2202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     // a series of set interval patterns.
2222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     // Only ERA, YEAR, MONTH, DATE,  DAY_OF_MONTH, DAY_OF_WEEK, AM_PM,  HOUR, HOUR_OF_DAY,
2232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     MINUTE and SECOND are supported.
2242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     dtitvinf.setIntervalPattern("yMMMd", Calendar.YEAR, "'y ~ y'");
2252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     dtitvinf.setIntervalPattern("yMMMd", Calendar.MONTH, "yyyy 'diff' MMM d - MMM d");
2262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     dtitvinf.setIntervalPattern("yMMMd", Calendar.DATE, "yyyy MMM d ~ d");
2272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     dtitvinf.setIntervalPattern("yMMMd", Calendar.HOUR_OF_DAY, "yyyy MMM d HH:mm ~ HH:mm");
2282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     // Set fallback interval pattern. Fallback pattern is used when interval pattern is not found.
2302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     // If the fall-back pattern is not set,  falls back to {date0} - {date1} if interval pattern is not found.
2312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     dtitvinf.setFallbackIntervalPattern("{0} - {1}");
2322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     // Set above DateIntervalInfo object as the interval patterns of date interval formatter
2342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     dtitvfmt.setDateIntervalInfo(dtitvinf);
2352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     // Prepare to format
2372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     pos = new FieldPosition(0);
2382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     str = new StringBuffer("");
2392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     // The 2 calendars should be equivalent, otherwise,  IllegalArgumentException will be thrown by format()
2412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     Calendar fromCalendar = (Calendar) dtfmt.getCalendar().clone();
2422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     Calendar toCalendar = (Calendar) dtfmt.getCalendar().clone();
2432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     fromCalendar.setTimeInMillis(....);
2442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     toCalendar.setTimeInMillis(...);
2452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     //Formatting given 2 calendars
2472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *     dtitvfmt.format(fromCalendar, toCalendar, str, pos);
2482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller *
2502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </pre>
2512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */
2522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpublic class DateIntervalFormat extends UFormat {
2542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final long serialVersionUID = 1;
2562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
2582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Used to save the information for a skeleton's best match skeleton.
2592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * It is package accessible since it is used in DateIntervalInfo too.
2602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    static final class BestMatchInfo {
2622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // the best match skeleton
2632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        final String bestMatchSkeleton;
2642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // 0 means the best matched skeleton is the same as input skeleton
2652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // 1 means the fields are the same, but field width are different
2662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // 2 means the only difference between fields are v/z,
2672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // -1 means there are other fields difference
2682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        final int    bestMatchDistanceInfo;
2692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        BestMatchInfo(String bestSkeleton, int difference) {
2702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            bestMatchSkeleton = bestSkeleton;
2712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            bestMatchDistanceInfo = difference;
2722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
2742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
2772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Used to save the information on a skeleton and its best match.
2782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static final class SkeletonAndItsBestMatch {
2802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        final String skeleton;
2812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        final String bestMatchSkeleton;
2822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        SkeletonAndItsBestMatch(String skeleton, String bestMatch) {
2832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            this.skeleton = skeleton;
2842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            bestMatchSkeleton = bestMatch;
2852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
2872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // Cache for the locale interval pattern
2902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static ICUCache<String, Map<String, PatternInfo>> LOCAL_PATTERN_CACHE =
2912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        new SimpleCache<String, Map<String, PatternInfo>>();
2922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
2942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The interval patterns for this locale.
2952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private DateIntervalInfo     fInfo;
2972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
2992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The DateFormat object used to format single pattern
3002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private SimpleDateFormat     fDateFormat;
3022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
3042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The 2 calendars with the from and to date.
3052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * could re-use the calendar in fDateFormat,
3062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * but keeping 2 calendars make it clear and clean.
3072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private Calendar fFromCalendar;
3092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private Calendar fToCalendar;
3102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
3122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Following are transient interval information
3132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * relevant (locale) to this formatter.
3142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private String fSkeleton = null;
3162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
3182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Needed for efficient deserialization. If set, it means we can use the
3192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * cache to initialize fIntervalPatterns.
3202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private boolean isDateIntervalInfoDefault;
3222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  Interval patterns for this instance's locale.
3252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private transient Map<String, PatternInfo> fIntervalPatterns = null;
3272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
3292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Patterns for fallback formatting.
3302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private String fDatePattern = null;
3322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private String fTimePattern = null;
3332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private String fDateTimeFormat = null;
3342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
3372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * default constructor; private because we don't want anyone to use
3382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @SuppressWarnings("unused")
3402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private DateIntervalFormat() {
3412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Construct a DateIntervalFormat from DateFormat,
3452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * a DateIntervalInfo, and skeleton.
3462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * DateFormat provides the timezone, calendar,
3472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * full pattern, and date format symbols information.
3482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * It should be a SimpleDateFormat object which
3492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * has a pattern in it.
3502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the DateIntervalInfo provides the interval patterns.
3512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
3522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param skeleton  the skeleton of the date formatter
3532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param dtItvInfo  the DateIntervalInfo object to be adopted.
3542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param simpleDateFormat will be used for formatting
3552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
3562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @deprecated This API is ICU internal only.
35793cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller     * @hide original deprecated declaration
358836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller     * @hide draft / provisional / internal are hidden on Android
3592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Deprecated
3612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public DateIntervalFormat(String skeleton, DateIntervalInfo dtItvInfo,
3622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                               SimpleDateFormat simpleDateFormat)
3632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
3642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fDateFormat = simpleDateFormat;
3652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // freeze date interval info
3662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        dtItvInfo.freeze();
3672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fSkeleton = skeleton;
3682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fInfo = dtItvInfo;
3692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        isDateIntervalInfoDefault = false;
3702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fFromCalendar = (Calendar) fDateFormat.getCalendar().clone();
3712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fToCalendar = (Calendar) fDateFormat.getCalendar().clone();
3722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        initializePattern(null);
3732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private DateIntervalFormat(String skeleton, ULocale locale,
3762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            SimpleDateFormat simpleDateFormat)
3772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
3782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fDateFormat = simpleDateFormat;
3792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fSkeleton = skeleton;
3802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fInfo = new DateIntervalInfo(locale).freeze();
3812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        isDateIntervalInfoDefault = true;
3822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fFromCalendar = (Calendar) fDateFormat.getCalendar().clone();
3832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fToCalendar = (Calendar) fDateFormat.getCalendar().clone();
3842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        initializePattern(LOCAL_PATTERN_CACHE);
3852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller}
3862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
3892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Construct a DateIntervalFormat from skeleton and  the default <code>FORMAT</code> locale.
3902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
3912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This is a convenient override of
3922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * getInstance(String skeleton, ULocale locale)
3932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * with the value of locale as default <code>FORMAT</code> locale.
3942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
3952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param skeleton  the skeleton on which interval format based.
3962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return          a date time interval formatter.
3972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see Category#FORMAT
3982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final DateIntervalFormat
4002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        getInstance(String skeleton)
4012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
4032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return getInstance(skeleton, ULocale.getDefault(Category.FORMAT));
4042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
4052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
4082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Construct a DateIntervalFormat from skeleton and a given locale.
4092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
4102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This is a convenient override of
4112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * getInstance(String skeleton, ULocale locale)
4122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
413cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller     * <p>Example code:{@sample external/icu/android_icu4j/src/samples/java/android/icu/samples/text/dateintervalformat/DateIntervalFormatSample.java dtitvfmtPreDefinedExample}
4142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param skeleton  the skeleton on which interval format based.
4152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param locale    the given locale
4162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return          a date time interval formatter.
4172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final DateIntervalFormat
4192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        getInstance(String skeleton, Locale locale)
4202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
4212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return getInstance(skeleton, ULocale.forLocale(locale));
4222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
4232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
4262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Construct a DateIntervalFormat from skeleton and a given locale.
4272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <P>
4282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * In this factory method,
4292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the date interval pattern information is load from resource files.
4302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Users are encouraged to created date interval formatter this way and
4312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * to use the pre-defined skeleton macros.
4322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
4332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <P>
4342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * There are pre-defined skeletons in DateFormat,
4352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * such as MONTH_DAY, YEAR_MONTH_WEEKDAY_DAY etc.
4362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
4372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Those skeletons have pre-defined interval patterns in resource files.
4382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Users are encouraged to use them.
4392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * For example:
4402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * DateIntervalFormat.getInstance(DateFormat.MONTH_DAY, false, loc);
4412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
4422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The given Locale provides the interval patterns.
4432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * For example, for en_GB, if skeleton is YEAR_ABBR_MONTH_WEEKDAY_DAY,
4442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * which is "yMMMEEEd",
4452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the interval patterns defined in resource file to above skeleton are:
4462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * "EEE, d MMM, yyyy - EEE, d MMM, yyyy" for year differs,
4472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * "EEE, d MMM - EEE, d MMM, yyyy" for month differs,
4482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * "EEE, d - EEE, d MMM, yyyy" for day differs,
4492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param skeleton  the skeleton on which interval format based.
4502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param locale    the given locale
4512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return          a date time interval formatter.
4522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final DateIntervalFormat
4542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        getInstance(String skeleton, ULocale locale)
4552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
4562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        DateTimePatternGenerator generator = DateTimePatternGenerator.getInstance(locale);
4572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return new DateIntervalFormat(skeleton, locale, new SimpleDateFormat(generator.getBestPattern(skeleton), locale));
4582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
4592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
4632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Construct a DateIntervalFormat from skeleton
4642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  DateIntervalInfo, and the default <code>FORMAT</code> locale.
4652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
4662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This is a convenient override of
4672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * getInstance(String skeleton, ULocale locale, DateIntervalInfo dtitvinf)
4682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * with the locale value as default <code>FORMAT</code> locale.
4692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
4702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param skeleton  the skeleton on which interval format based.
4712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param dtitvinf  the DateIntervalInfo object to be adopted.
4722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return          a date time interval formatter.
4732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @see Category#FORMAT
4742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final DateIntervalFormat getInstance(String skeleton,
4762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                   DateIntervalInfo dtitvinf)
4772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
4782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return getInstance(skeleton, ULocale.getDefault(Category.FORMAT), dtitvinf);
4792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
4802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
4842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Construct a DateIntervalFormat from skeleton
4852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * a DateIntervalInfo, and the given locale.
4862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
4872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This is a convenient override of
4882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * getInstance(String skeleton, ULocale locale, DateIntervalInfo dtitvinf)
4892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
490cc49f813b0d7bf6664102b30b5513fd21c362e0dNeil Fuller     * <p>Example code:{@sample external/icu/android_icu4j/src/samples/java/android/icu/samples/text/dateintervalformat/DateIntervalFormatSample.java dtitvfmtCustomizedExample}
4912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param skeleton  the skeleton on which interval format based.
4922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param locale    the given locale
4932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param dtitvinf  the DateIntervalInfo object to be adopted.
4942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return          a date time interval formatter.
4952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final DateIntervalFormat getInstance(String skeleton,
4972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                 Locale locale,
4982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                 DateIntervalInfo dtitvinf)
4992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
5002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return getInstance(skeleton, ULocale.forLocale(locale), dtitvinf);
5012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
5062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Construct a DateIntervalFormat from skeleton
5072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * a DateIntervalInfo, and the given locale.
5082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
5092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <P>
5102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * In this factory method, user provides its own date interval pattern
5112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * information, instead of using those pre-defined data in resource file.
5122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This factory method is for powerful users who want to provide their own
5132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * interval patterns.
5142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
5152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <P>
5162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * There are pre-defined skeleton in DateFormat,
5172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * such as MONTH_DAY, YEAR_MONTH_WEEKDAY_DAY etc.
5182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
5192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Those skeletons have pre-defined interval patterns in resource files.
5202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Users are encouraged to use them.
5212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * For example:
5222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * DateIntervalFormat.getInstance(DateFormat.MONTH_DAY, false, loc,itvinf);
5232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
5242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the DateIntervalInfo provides the interval patterns.
5252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
5262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * User are encouraged to set default interval pattern in DateIntervalInfo
5272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * as well, if they want to set other interval patterns ( instead of
5282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * reading the interval patterns from resource files).
5292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * When the corresponding interval pattern for a largest calendar different
5302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * field is not found ( if user not set it ), interval format fallback to
5312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the default interval pattern.
5322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If user does not provide default interval pattern, it fallback to
5332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * "{date0} - {date1}"
5342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
5352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param skeleton  the skeleton on which interval format based.
5362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param locale    the given locale
5372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param dtitvinf  the DateIntervalInfo object to be adopted.
5382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return          a date time interval formatter.
5392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static final DateIntervalFormat getInstance(String skeleton,
5412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                 ULocale locale,
5422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                 DateIntervalInfo dtitvinf)
5432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
5442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // clone. If it is frozen, clone returns itself, otherwise, clone
5452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // returns a copy.
5462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        dtitvinf = (DateIntervalInfo)dtitvinf.clone();
5472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        DateTimePatternGenerator generator = DateTimePatternGenerator.getInstance(locale);
5482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return new DateIntervalFormat(skeleton, dtitvinf, new SimpleDateFormat(generator.getBestPattern(skeleton), locale));
5492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
5532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Clone this Format object polymorphically.
5542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return    A copy of the object.
5552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Object clone()
5572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
5582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        DateIntervalFormat other = (DateIntervalFormat) super.clone();
5592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        other.fDateFormat = (SimpleDateFormat) fDateFormat.clone();
5602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        other.fInfo = (DateIntervalInfo) fInfo.clone();
5612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        other.fFromCalendar = (Calendar) fFromCalendar.clone();
5622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        other.fToCalendar = (Calendar) fToCalendar.clone();
5632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        other.fDatePattern = fDatePattern;
5642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        other.fTimePattern = fTimePattern;
5652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        other.fDateTimeFormat = fDateTimeFormat;
5662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return other;
5672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
5712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Format an object to produce a string. This method handles Formattable
5722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * objects with a DateInterval type.
5732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * If a the Formattable object type is not a DateInterval,
5742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * IllegalArgumentException is thrown.
5752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
5762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param obj               The object to format.
5772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          Must be a DateInterval.
5782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param appendTo          Output parameter to receive result.
5792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          Result is appended to existing contents.
5802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param fieldPosition     On input: an alignment field, if desired.
5812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          On output: the offsets of the alignment field.
5822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          There may be multiple instances of a given field type
5832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          in an interval format; in this case the fieldPosition
5842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          offsets refer to the first instance.
5852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return                  Reference to 'appendTo' parameter.
5862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws    IllegalArgumentException  if the formatted object is not
5872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                                      DateInterval object
5882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public final StringBuffer
5902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        format(Object obj, StringBuffer appendTo, FieldPosition fieldPosition)
5912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
5922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( obj instanceof DateInterval ) {
5932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return format( (DateInterval)obj, appendTo, fieldPosition);
5942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        else {
5962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("Cannot format given Object (" + obj.getClass().getName() + ") as a DateInterval");
5972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
6012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Format a DateInterval to produce a string.
6022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
6032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param dtInterval        DateInterval to be formatted.
6042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param appendTo          Output parameter to receive result.
6052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          Result is appended to existing contents.
6062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param fieldPosition     On input: an alignment field, if desired.
6072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          On output: the offsets of the alignment field.
6082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          There may be multiple instances of a given field type
6092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          in an interval format; in this case the fieldPosition
6102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          offsets refer to the first instance.
6112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return                  Reference to 'appendTo' parameter.
6122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
6132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public final StringBuffer format(DateInterval dtInterval,
6142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                     StringBuffer appendTo,
6152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                     FieldPosition fieldPosition)
6162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
6172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fFromCalendar.setTimeInMillis(dtInterval.getFromDate());
6182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fToCalendar.setTimeInMillis(dtInterval.getToDate());
6192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return format(fFromCalendar, fToCalendar, appendTo, fieldPosition);
6202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
6212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
6232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @deprecated This API is ICU internal only.
62493cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller     * @hide original deprecated declaration
625836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller     * @hide draft / provisional / internal are hidden on Android
6262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
6272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Deprecated
6282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public String getPatterns(Calendar fromCalendar,
6292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            Calendar toCalendar,
6302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            Output<String> part2) {
6312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // First, find the largest different calendar field.
6322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int field;
6332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( fromCalendar.get(Calendar.ERA) != toCalendar.get(Calendar.ERA) ) {
6342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            field = Calendar.ERA;
6352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if ( fromCalendar.get(Calendar.YEAR) !=
6362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    toCalendar.get(Calendar.YEAR) ) {
6372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            field = Calendar.YEAR;
6382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if ( fromCalendar.get(Calendar.MONTH) !=
6392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    toCalendar.get(Calendar.MONTH) ) {
6402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            field = Calendar.MONTH;
6412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if ( fromCalendar.get(Calendar.DATE) !=
6422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    toCalendar.get(Calendar.DATE) ) {
6432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            field = Calendar.DATE;
6442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if ( fromCalendar.get(Calendar.AM_PM) !=
6452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    toCalendar.get(Calendar.AM_PM) ) {
6462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            field = Calendar.AM_PM;
6472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if ( fromCalendar.get(Calendar.HOUR) !=
6482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    toCalendar.get(Calendar.HOUR) ) {
6492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            field = Calendar.HOUR;
6502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if ( fromCalendar.get(Calendar.MINUTE) !=
6512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    toCalendar.get(Calendar.MINUTE) ) {
6522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            field = Calendar.MINUTE;
6532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if ( fromCalendar.get(Calendar.SECOND) !=
6542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    toCalendar.get(Calendar.SECOND) ) {
6552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            field = Calendar.SECOND;
6562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
6572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return null;
6582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
6592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        PatternInfo intervalPattern = fIntervalPatterns.get(
6602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[field]);
6612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        part2.value = intervalPattern.getSecondPart();
6622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return intervalPattern.getFirstPart();
6632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
6642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
6652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Format 2 Calendars to produce a string.
6662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
6672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param fromCalendar      calendar set to the from date in date interval
6682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          to be formatted into date interval string
6692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param toCalendar        calendar set to the to date in date interval
6702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          to be formatted into date interval string
6712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param appendTo          Output parameter to receive result.
6722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          Result is appended to existing contents.
6732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param pos               On input: an alignment field, if desired.
6742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          On output: the offsets of the alignment field.
6752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          There may be multiple instances of a given field type
6762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          in an interval format; in this case the fieldPosition
6772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          offsets refer to the first instance.
6782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return                  Reference to 'appendTo' parameter.
6792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws    IllegalArgumentException  if the two calendars are not equivalent.
6802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
6812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public final StringBuffer format(Calendar fromCalendar,
6822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                     Calendar toCalendar,
6832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                     StringBuffer appendTo,
6842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                     FieldPosition pos)
6852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
6862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // not support different calendar types and time zones
6872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( !fromCalendar.isEquivalentTo(toCalendar) ) {
6882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("can not format on two different calendars");
6892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
6902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // First, find the largest different calendar field.
6922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int field = -1; //init with an invalid value.
6932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
6942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( fromCalendar.get(Calendar.ERA) != toCalendar.get(Calendar.ERA) ) {
6952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            field = Calendar.ERA;
6962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if ( fromCalendar.get(Calendar.YEAR) !=
6972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    toCalendar.get(Calendar.YEAR) ) {
6982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            field = Calendar.YEAR;
6992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if ( fromCalendar.get(Calendar.MONTH) !=
7002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    toCalendar.get(Calendar.MONTH) ) {
7012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            field = Calendar.MONTH;
7022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if ( fromCalendar.get(Calendar.DATE) !=
7032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    toCalendar.get(Calendar.DATE) ) {
7042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            field = Calendar.DATE;
7052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if ( fromCalendar.get(Calendar.AM_PM) !=
7062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    toCalendar.get(Calendar.AM_PM) ) {
7072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            field = Calendar.AM_PM;
7082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if ( fromCalendar.get(Calendar.HOUR) !=
7092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    toCalendar.get(Calendar.HOUR) ) {
7102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            field = Calendar.HOUR;
7112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if ( fromCalendar.get(Calendar.MINUTE) !=
7122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    toCalendar.get(Calendar.MINUTE) ) {
7132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            field = Calendar.MINUTE;
7142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         } else if ( fromCalendar.get(Calendar.SECOND) !=
7152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    toCalendar.get(Calendar.SECOND) ) {
7162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            field = Calendar.SECOND;
7172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller       } else {
7182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* ignore the millisecond etc. small fields' difference.
7192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * use single date when all the above are the same.
7202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             */
7212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return fDateFormat.format(fromCalendar, appendTo, pos);
7222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
7232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean fromToOnSameDay = (field==Calendar.AM_PM || field==Calendar.HOUR || field==Calendar.MINUTE || field==Calendar.SECOND);
7242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // get interval pattern
7262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        PatternInfo intervalPattern = fIntervalPatterns.get(
7272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[field]);
7282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( intervalPattern == null ) {
7302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( fDateFormat.isFieldUnitIgnored(field) ) {
7312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                /* the largest different calendar field is small than
7322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 * the smallest calendar field in pattern,
7332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 * return single date format.
7342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 */
7352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return fDateFormat.format(fromCalendar, appendTo, pos);
7362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
7372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, pos);
7392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
7402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // If the first part in interval pattern is empty,
7422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // the 2nd part of it saves the full-pattern used in fall-back.
7432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // For a 'real' interval pattern, the first part will never be empty.
7442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( intervalPattern.getFirstPart() == null ) {
7452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // fall back
7462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, pos,
7472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    intervalPattern.getSecondPart());
7482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
7492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Calendar firstCal;
7502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Calendar secondCal;
7512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( intervalPattern.firstDateInPtnIsLaterDate() ) {
7522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            firstCal = toCalendar;
7532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            secondCal = fromCalendar;
7542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
7552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            firstCal = fromCalendar;
7562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            secondCal = toCalendar;
7572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
7582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // break the interval pattern into 2 parts
7592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // first part should not be empty,
7602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String originalPattern = fDateFormat.toPattern();
7612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fDateFormat.applyPattern(intervalPattern.getFirstPart());
7622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fDateFormat.format(firstCal, appendTo, pos);
7632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( intervalPattern.getSecondPart() != null ) {
7642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            fDateFormat.applyPattern(intervalPattern.getSecondPart());
7652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            FieldPosition otherPos = new FieldPosition(pos.getField());
7662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            fDateFormat.format(secondCal, appendTo, otherPos);
7672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (pos.getEndIndex() == 0 && otherPos.getEndIndex() > 0) {
7682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                pos = otherPos;
7692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
7702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
7712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fDateFormat.applyPattern(originalPattern);
7722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return appendTo;
7732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
7742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
7752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void adjustPosition(String combiningPattern, // has {0} and {1} in it
7762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                String pat0, FieldPosition pos0, // pattern and pos corresponding to {0}
7772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                String pat1, FieldPosition pos1, // pattern and pos corresponding to {1}
7782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                FieldPosition posResult) {
7792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int index0 = combiningPattern.indexOf("{0}");
7802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int index1 = combiningPattern.indexOf("{1}");
7812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (index0 < 0 || index1 < 0) {
7822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
7832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
7842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int placeholderLen = 3; // length of "{0}" or "{1}"
7852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (index0 < index1) {
7862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (pos0.getEndIndex() > 0) {
7872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                posResult.setBeginIndex(pos0.getBeginIndex() + index0);
7882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                posResult.setEndIndex(pos0.getEndIndex() + index0);
7892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (pos1.getEndIndex() > 0) {
7902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // here index1 >= 3
7912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                index1 += pat0.length() - placeholderLen; // adjust for pat0 replacing {0}
7922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                posResult.setBeginIndex(pos1.getBeginIndex() + index1);
7932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                posResult.setEndIndex(pos1.getEndIndex() + index1);
7942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
7952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
7962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (pos1.getEndIndex() > 0) {
7972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                posResult.setBeginIndex(pos1.getBeginIndex() + index1);
7982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                posResult.setEndIndex(pos1.getEndIndex() + index1);
7992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (pos0.getEndIndex() > 0) {
8002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // here index0 >= 3
8012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                index0 += pat1.length() - placeholderLen; // adjust for pat1 replacing {1}
8022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                posResult.setBeginIndex(pos0.getBeginIndex() + index0);
8032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                posResult.setEndIndex(pos0.getEndIndex() + index0);
8042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
8052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
8062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
8072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
8092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Format 2 Calendars to using fall-back interval pattern
8102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
8112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The full pattern used in this fall-back format is the
8122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * full pattern of the date formatter.
8132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
8142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param fromCalendar      calendar set to the from date in date interval
8152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          to be formatted into date interval string
8162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param toCalendar        calendar set to the to date in date interval
8172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          to be formatted into date interval string
8182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param appendTo          Output parameter to receive result.
8192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          Result is appended to existing contents.
8202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param pos               On input: an alignment field, if desired.
8212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          On output: the offsets of the alignment field.
8222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return                  Reference to 'appendTo' parameter.
8232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private final StringBuffer fallbackFormat(Calendar fromCalendar,
8252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                              Calendar toCalendar,
8262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                              boolean fromToOnSameDay,
8272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                              StringBuffer appendTo,
8282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                              FieldPosition pos)  {
8292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String fullPattern = null; // for saving the pattern in fDateFormat
8302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            boolean formatDatePlusTimeRange = (fromToOnSameDay && fDatePattern != null && fTimePattern != null);
8312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // the fall back
8322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (formatDatePlusTimeRange) {
8332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                fullPattern = fDateFormat.toPattern(); // save current pattern, restore later
8342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                fDateFormat.applyPattern(fTimePattern);
8352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
8362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            FieldPosition otherPos = new FieldPosition(pos.getField());
8372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            StringBuffer earlierDate = new StringBuffer(64);
8382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            earlierDate = fDateFormat.format(fromCalendar, earlierDate, pos);
8392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            StringBuffer laterDate = new StringBuffer(64);
8402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            laterDate = fDateFormat.format(toCalendar, laterDate, otherPos);
8412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String fallbackPattern = fInfo.getFallbackIntervalPattern();
8422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            adjustPosition(fallbackPattern, earlierDate.toString(), pos, laterDate.toString(), otherPos, pos);
8432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String fallbackRange = MessageFormat.format(fallbackPattern, new Object[]
8442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            {earlierDate.toString(), laterDate.toString()});
8452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (formatDatePlusTimeRange) {
8462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // fallbackRange has just the time range, need to format the date part and combine that
8472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                fDateFormat.applyPattern(fDatePattern);
8482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                StringBuffer datePortion = new StringBuffer(64);
8492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                otherPos.setBeginIndex(0);
8502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                otherPos.setEndIndex(0);
8512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                datePortion = fDateFormat.format(fromCalendar, datePortion, otherPos);
8522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                adjustPosition(fDateTimeFormat, fallbackRange, pos, datePortion.toString(), otherPos, pos);
8532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                fallbackRange = MessageFormat.format(fDateTimeFormat, new Object[]
8542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            {fallbackRange, datePortion.toString()});
8552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
8562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            appendTo.append(fallbackRange);
8572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (formatDatePlusTimeRange) {
8582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // restore full pattern
8592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                fDateFormat.applyPattern(fullPattern);
8602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
8612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return appendTo;
8622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
8632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
8662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Format 2 Calendars to using fall-back interval pattern
8672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
8682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This fall-back pattern is generated on a given full pattern,
8692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * not the full pattern of the date formatter.
8702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
8712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param fromCalendar      calendar set to the from date in date interval
8722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          to be formatted into date interval string
8732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param toCalendar        calendar set to the to date in date interval
8742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          to be formatted into date interval string
8752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param appendTo          Output parameter to receive result.
8762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          Result is appended to existing contents.
8772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param pos               On input: an alignment field, if desired.
8782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                          On output: the offsets of the alignment field.
8792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param fullPattern       the full pattern need to apply to date formatter
8802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return                  Reference to 'appendTo' parameter.
8812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
8822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private final StringBuffer fallbackFormat(Calendar fromCalendar,
8832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                              Calendar toCalendar,
8842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                              boolean fromToOnSameDay,
8852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                              StringBuffer appendTo,
8862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                              FieldPosition pos,
8872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                              String fullPattern)  {
8882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String originalPattern = fDateFormat.toPattern();
8892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            fDateFormat.applyPattern(fullPattern);
8902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, pos);
8912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            fDateFormat.applyPattern(originalPattern);
8922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return appendTo;
8932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
8942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
8962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
8972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Date interval parsing is not supported.
8982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <P>
8992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This method should handle parsing of
9002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * date time interval strings into Formattable objects with
9012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * DateInterval type, which is a pair of UDate.
9022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <P>
9032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Before calling, set parse_pos.index to the offset you want to start
9042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * parsing at in the source. After calling, parse_pos.index is the end of
9052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the text you parsed. If error occurs, index is unchanged.
9062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <P>
9072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * When parsing, leading whitespace is discarded (with a successful parse),
9082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * while trailing whitespace is left as is.
9092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * <P>
9102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * See Format.parseObject() for more.
9112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
9122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param source    The string to be parsed into an object.
9132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param parse_pos The position to start parsing at. Since no parsing
9142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                  is supported, upon return this param is unchanged.
9152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return          A newly created Formattable* object, or NULL
9162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                  on failure.
9172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @deprecated This API is ICU internal only.
91893cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller     * @hide original deprecated declaration
919836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller     * @hide draft / provisional / internal are hidden on Android
9202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Deprecated
9222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Object parseObject(String source, ParsePosition parse_pos)
9232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
9242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        throw new UnsupportedOperationException("parsing is not supported");
9252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
9262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
9292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Gets the date time interval patterns.
9302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return a copy of the date time interval patterns associated with
9312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * this date interval formatter.
9322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public DateIntervalInfo getDateIntervalInfo()
9342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
9352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return (DateIntervalInfo)fInfo.clone();
9362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
9372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
9402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Set the date time interval patterns.
9412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param newItvPattern   the given interval patterns to copy.
9422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void setDateIntervalInfo(DateIntervalInfo newItvPattern)
9442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
9452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // clone it. If it is frozen, the clone returns itself.
9462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Otherwise, clone returns a copy
9472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fInfo = (DateIntervalInfo)newItvPattern.clone();
9482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        this.isDateIntervalInfoDefault = false;
9492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fInfo.freeze(); // freeze it
9502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( fDateFormat != null ) {
9512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            initializePattern(null);
9522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
9532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
9542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
9562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the TimeZone
9572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return A copy of the TimeZone associated with this date interval formatter.
9582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public TimeZone getTimeZone()
9602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
9612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( fDateFormat != null ) {
9622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Here we clone, like other getters here, but unlike
9632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // DateFormat.getTimeZone() and Calendar.getTimeZone()
9642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // which return the TimeZone from the Calendar's zone variable
9652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return (TimeZone)(fDateFormat.getTimeZone().clone());
9662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
9672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // If fDateFormat is null (unexpected), return default timezone.
9682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return TimeZone.getDefault();
9692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
9702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
9732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Set the TimeZone for the calendar used by this DateIntervalFormat object.
9742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param zone The new TimeZone, will be cloned for use by this DateIntervalFormat.
9752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void setTimeZone(TimeZone zone)
9772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
9782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // zone is cloned once for all three usages below:
9792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        TimeZone zoneToSet = (TimeZone)zone.clone();
9802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (fDateFormat != null) {
9812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            fDateFormat.setTimeZone(zoneToSet);
9822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
9832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // fDateFormat has the master calendar for the DateIntervalFormat;
9842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // fFromCalendar and fToCalendar are internal work clones of that calendar.
9852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (fFromCalendar != null) {
9862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            fFromCalendar.setTimeZone(zoneToSet);
9872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
9882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (fToCalendar != null) {
9892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            fToCalendar.setTimeZone(zoneToSet);
9902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
9912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
9922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
9932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
9942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Gets the date formatter
9952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return a copy of the date formatter associated with
9962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * this date interval formatter.
9972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
9982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public DateFormat getDateFormat()
9992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
10002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return (DateFormat)fDateFormat.clone();
10012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
10022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
10052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  Below are for generating interval patterns locale to the formatter
10062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
10092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Initialize interval patterns locale to this formatter.
10102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void initializePattern(ICUCache<String, Map<String, PatternInfo>> cache) {
10122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String fullPattern = fDateFormat.toPattern();
10132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        ULocale locale = fDateFormat.getLocale();
10142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String key = null;
10152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Map<String, PatternInfo> patterns = null;
10162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (cache != null) {
10172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( fSkeleton != null ) {
10182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                key = locale.toString() + "+" + fullPattern + "+" + fSkeleton;
10192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
10202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                key = locale.toString() + "+" + fullPattern;
10212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
10222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            patterns = cache.get(key);
10232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
10242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (patterns == null) {
10252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            Map<String, PatternInfo> intervalPatterns = initializeIntervalPattern(fullPattern, locale);
10262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            patterns = Collections.unmodifiableMap(intervalPatterns);
10272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (cache != null) {
10282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                cache.put(key, patterns);
10292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
10302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
10312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        fIntervalPatterns = patterns;
10322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
10332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
10372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Initialize interval patterns locale to this formatter
10382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
10392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This code is a bit complicated since
10402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 1. the interval patterns saved in resource bundle files are interval
10412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    patterns based on date or time only.
10422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    It does not have interval patterns based on both date and time.
10432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    Interval patterns on both date and time are algorithm generated.
10442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
10452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    For example, it has interval patterns on skeleton "dMy" and "hm",
10462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    but it does not have interval patterns on skeleton "dMyhm".
10472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
10482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    The rule to generate interval patterns for both date and time skeleton are
10492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    1) when the year, month, or day differs, concatenate the two original
10502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    expressions with a separator between,
10512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    For example, interval pattern from "Jan 10, 2007 10:10 am"
10522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    to "Jan 11, 2007 10:10am" is
10532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    "Jan 10, 2007 10:10 am - Jan 11, 2007 10:10am"
10542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
10552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    2) otherwise, present the date followed by the range expression
10562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    for the time.
10572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    For example, interval pattern from "Jan 10, 2007 10:10 am"
10582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    to "Jan 10, 2007 11:10am" is
10592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    "Jan 10, 2007 10:10 am - 11:10am"
10602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
10612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 2. even a pattern does not request a certain calendar field,
10622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    the interval pattern needs to include such field if such fields are
10632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    different between 2 dates.
10642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    For example, a pattern/skeleton is "hm", but the interval pattern
10652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    includes year, month, and date when year, month, and date differs.
10662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
10672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
10682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param fullPattern  formatter's full pattern
10692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param locale       the given locale.
10702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return             interval patterns' hash map
10712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
10722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private Map<String, PatternInfo> initializeIntervalPattern(String fullPattern, ULocale locale) {
10732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        DateTimePatternGenerator dtpng = DateTimePatternGenerator.getInstance(locale);
10742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( fSkeleton == null ) {
10752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // fSkeleton is already set by getDateIntervalInstance()
10762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // or by getInstance(String skeleton, .... )
10772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            fSkeleton = dtpng.getSkeleton(fullPattern);
10782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
10792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String skeleton = fSkeleton;
10802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        HashMap<String, PatternInfo> intervalPatterns = new HashMap<String, PatternInfo>();
10822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* Check whether the skeleton is a combination of date and time.
10842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * For the complication reason 1 explained above.
10852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
10862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        StringBuilder date = new StringBuilder(skeleton.length());
10872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        StringBuilder normalizedDate = new StringBuilder(skeleton.length());
10882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        StringBuilder time = new StringBuilder(skeleton.length());
10892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        StringBuilder normalizedTime = new StringBuilder(skeleton.length());
10902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
10912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* the difference between time skeleton and normalizedTimeSkeleton are:
10922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * 1. (Formerly, normalized time skeleton folded 'H' to 'h'; no longer true)
10932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * 2. 'a' is omitted in normalized time skeleton.
10942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * 3. there is only one appearance for 'h', 'm','v', 'z' in normalized
10952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         *    time skeleton
10962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         *
10972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * The difference between date skeleton and normalizedDateSkeleton are:
10982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * 1. both 'y' and 'd' appear only once in normalizeDateSkeleton
10992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * 2. 'E' and 'EE' are normalized into 'EEE'
11002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * 3. 'MM' is normalized into 'M'
11012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
11022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        getDateTimeSkeleton(skeleton, date, normalizedDate,
11032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            time, normalizedTime);
11042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String dateSkeleton = date.toString();
11062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String timeSkeleton = time.toString();
11072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String normalizedDateSkeleton = normalizedDate.toString();
11082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String normalizedTimeSkeleton = normalizedTime.toString();
11092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // move this up here since we need it for fallbacks
11112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (time.length() != 0 && date.length() != 0) {
11122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Need the Date/Time pattern for concatnation the date with
11132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // the time interval.
11142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // The date/time pattern ( such as {0} {1} ) is saved in
11152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // calendar, that is why need to get the CalendarData here.
11162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            CalendarData calData = new CalendarData(locale, null);
11172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String[] patterns = calData.getDateTimePatterns();
11182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            fDateTimeFormat = patterns[8];
11192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
11202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean found = genSeparateDateTimePtn(normalizedDateSkeleton,
11222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                               normalizedTimeSkeleton,
11232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                               intervalPatterns, dtpng);
11242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
11252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // for skeletons with seconds, found is false and we enter this block
11262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( found == false ) {
11272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // use fallback
11282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // TODO: if user asks "m", but "d" differ
11292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            //StringBuffer skeleton = new StringBuffer(skeleton);
11302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( time.length() != 0 ) {
11312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                //genFallbackForNotFound(Calendar.MINUTE, skeleton);
11322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                //genFallbackForNotFound(Calendar.HOUR, skeleton);
11332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                //genFallbackForNotFound(Calendar.AM_PM, skeleton);
11342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ( date.length() == 0 ) {
11352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // prefix with yMd
11362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    timeSkeleton = DateFormat.YEAR_NUM_MONTH_DAY + timeSkeleton;
11372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    String pattern =dtpng.getBestPattern(timeSkeleton);
11382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // for fall back interval patterns,
11392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // the first part of the pattern is empty,
11402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // the second part of the pattern is the full-pattern
11412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // should be used in fall-back.
11422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    PatternInfo ptn = new PatternInfo(null, pattern,
11432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                     fInfo.getDefaultOrder());
11442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    intervalPatterns.put(DateIntervalInfo.
11452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.DATE], ptn);
11462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // share interval pattern
11472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    intervalPatterns.put(DateIntervalInfo.
11482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.MONTH], ptn);
11492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // share interval pattern
11502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    intervalPatterns.put(DateIntervalInfo.
11512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.YEAR], ptn);
11522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
11532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    //genFallbackForNotFound(Calendar.DATE, skeleton);
11542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    //genFallbackForNotFound(Calendar.MONTH, skeleton);
11552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    //genFallbackForNotFound(Calendar.YEAR, skeleton);
11562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
11572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
11582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    //genFallbackForNotFound(Calendar.DATE, skeleton);
11592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    //genFallbackForNotFound(Calendar.MONTH, skeleton);
11602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    //genFallbackForNotFound(Calendar.YEAR, skeleton);
11612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
11622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return intervalPatterns;
11632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } // end of skeleton not found
11642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // interval patterns for skeleton are found in resource
11652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( time.length() == 0 ) {
11662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // done
11672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if ( date.length() == 0 ) {
11682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // need to set up patterns for y/M/d differ
11692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* result from following looks confusing.
11702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * for example: 10 10:10 - 11 10:10, it is not
11712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * clear that the first 10 is the 10th day
11722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            time.insert(0, 'd');
11732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            genFallbackPattern(Calendar.DATE, time);
11742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            time.insert(0, 'M');
11752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            genFallbackPattern(Calendar.MONTH, time);
11762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            time.insert(0, 'y');
11772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            genFallbackPattern(Calendar.YEAR, time);
11782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            */
11792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // prefix with yMd
11802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            timeSkeleton = DateFormat.YEAR_NUM_MONTH_DAY + timeSkeleton;
11812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String pattern =dtpng.getBestPattern(timeSkeleton);
11822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // for fall back interval patterns,
11832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // the first part of the pattern is empty,
11842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // the second part of the pattern is the full-pattern
11852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // should be used in fall-back.
11862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            PatternInfo ptn = new PatternInfo(
11872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    null, pattern, fInfo.getDefaultOrder());
11882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            intervalPatterns.put(DateIntervalInfo.
11892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.DATE], ptn);
11902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            intervalPatterns.put(DateIntervalInfo.
11912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.MONTH], ptn);
11922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            intervalPatterns.put(DateIntervalInfo.
11932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.YEAR], ptn);
11942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
11952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /* if both present,
11962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * 1) when the year, month, or day differs,
11972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * concatenate the two original expressions with a separator between,
11982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * 2) otherwise, present the date followed by the
11992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * range expression for the time.
12002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             */
12012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /*
12022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * 1) when the year, month, or day differs,
12032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * concatenate the two original expressions with a separator between,
12042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             */
12052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // if field exists, use fall back
12062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( !fieldExistsInSkeleton(Calendar.DATE, dateSkeleton) ) {
12072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // prefix skeleton with 'd'
12082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                skeleton = DateIntervalInfo.
12092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.DATE] + skeleton;
12102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                genFallbackPattern(Calendar.DATE, skeleton, intervalPatterns, dtpng);
12112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
12122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( !fieldExistsInSkeleton(Calendar.MONTH, dateSkeleton) ) {
12132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // then prefix skeleton with 'M'
12142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                skeleton = DateIntervalInfo.
12152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.MONTH] + skeleton;
12162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                genFallbackPattern(Calendar.MONTH, skeleton, intervalPatterns, dtpng);
12172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
12182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( !fieldExistsInSkeleton(Calendar.YEAR, dateSkeleton) ) {
12192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // then prefix skeleton with 'y'
12202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                skeleton = DateIntervalInfo.
12212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.YEAR] + skeleton;
12222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                genFallbackPattern(Calendar.YEAR, skeleton, intervalPatterns, dtpng);
12232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
12242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            /*
12262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * 2) otherwise, present the date followed by the
12272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             * range expression for the time.
12282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller             */
12292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (fDateTimeFormat == null) {
12302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                fDateTimeFormat = "{1} {0}";
12312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
12322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String datePattern =dtpng.getBestPattern(dateSkeleton);
12332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            concatSingleDate2TimeInterval(fDateTimeFormat, datePattern, Calendar.AM_PM, intervalPatterns);
12342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            concatSingleDate2TimeInterval(fDateTimeFormat, datePattern, Calendar.HOUR, intervalPatterns);
12352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            concatSingleDate2TimeInterval(fDateTimeFormat, datePattern, Calendar.MINUTE, intervalPatterns);
12362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
12372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return intervalPatterns;
12392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
12432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Generate fall back interval pattern given a calendar field,
12442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * a skeleton, and a date time pattern generator
12452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param field      the largest different calendar field
12462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param skeleton   a skeleton
12472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param dtpng      date time pattern generator
12482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param intervalPatterns interval patterns
12492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
12502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void genFallbackPattern(int field, String skeleton,
12512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    Map<String, PatternInfo> intervalPatterns,
12522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    DateTimePatternGenerator dtpng) {
12532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String pattern = dtpng.getBestPattern(skeleton);
12542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // for fall back interval patterns,
12552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // the first part of the pattern is empty,
12562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // the second part of the pattern is the full-pattern
12572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // should be used in fall-back.
12582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        PatternInfo ptn = new PatternInfo(
12592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    null, pattern, fInfo.getDefaultOrder());
12602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        intervalPatterns.put(
12612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[field], ptn);
12622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
12672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void genFallbackForNotFound(String field, StringBuffer skeleton) {
12682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( SimpleDateFormat.isFieldUnitIgnored(skeleton.toString(), field) ) {
12692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // single date
12702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            DateIntervalInfo.PatternInfo ptnInfo =
12712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                new DateIntervalInfo.PatternInfo(null, fDateFormat.toPattern(),
12722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                 fInfo.getDefaultOrder());
12732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            fIntervalPatterns.put(field, ptnInfo);
12742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
12752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if ( skeleton.indexOf(field) == -1 ) {
12762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            skeleton.insert(0,field);
12772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            genFallbackPattern(field, skeleton, dtpng);
12782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
12792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
12802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    */
12812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
12822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
12832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * get separated date and time skeleton from a combined skeleton.
12842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
12852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The difference between date skeleton and normalizedDateSkeleton are:
12862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 1. both 'y' and 'd' are appeared only once in normalizeDateSkeleton
12872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 2. 'E' and 'EE' are normalized into 'EEE'
12882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 3. 'MM' is normalized into 'M'
12892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
12902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     ** the difference between time skeleton and normalizedTimeSkeleton are:
12912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 1. both 'H' and 'h' are normalized as 'h' in normalized time skeleton,
12922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 2. 'a' is omitted in normalized time skeleton.
12932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 3. there is only one appearance for 'h', 'm','v', 'z' in normalized time
12942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    skeleton
12952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
12962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
12972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  @param skeleton               given combined skeleton.
12982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  @param date                   Output parameter for date only skeleton.
12992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  @param normalizedDate         Output parameter for normalized date only
13002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
13012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  @param time                   Output parameter for time only skeleton.
13022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *  @param normalizedTime         Output parameter for normalized time only
13032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                                skeleton.
13042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
13052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static void getDateTimeSkeleton(String skeleton,
13062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                            StringBuilder dateSkeleton,
13072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                            StringBuilder normalizedDateSkeleton,
13082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                            StringBuilder timeSkeleton,
13092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                            StringBuilder normalizedTimeSkeleton)
13102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
13112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // dateSkeleton follows the sequence of y*M*E*d*
13122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // timeSkeleton follows the sequence of hm*[v|z]?
13132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int i;
13142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int ECount = 0;
13152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int dCount = 0;
13162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int MCount = 0;
13172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int yCount = 0;
13182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int hCount = 0;
13192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int HCount = 0;
13202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int mCount = 0;
13212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int vCount = 0;
13222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int zCount = 0;
13232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
13242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (i = 0; i < skeleton.length(); ++i) {
13252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            char ch = skeleton.charAt(i);
13262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            switch ( ch ) {
13272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'E':
13282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                dateSkeleton.append(ch);
13292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ++ECount;
13302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
13312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'd':
13322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                dateSkeleton.append(ch);
13332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ++dCount;
13342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
13352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'M':
13362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                dateSkeleton.append(ch);
13372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ++MCount;
13382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
13392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'y':
13402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                dateSkeleton.append(ch);
13412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ++yCount;
13422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
13432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'G':
13442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'Y':
13452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'u':
13462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'Q':
13472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'q':
13482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'L':
13492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'l':
13502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'W':
13512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'w':
13522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'D':
13532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'F':
13542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'g':
13552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'e':
13562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'c':
13572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'U':
13582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'r':
13592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                normalizedDateSkeleton.append(ch);
13602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                dateSkeleton.append(ch);
13612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
13622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'a':
13632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // 'a' is implicitly handled
13642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                timeSkeleton.append(ch);
13652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
13662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'h':
13672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                timeSkeleton.append(ch);
13682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ++hCount;
13692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
13702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'H':
13712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                timeSkeleton.append(ch);
13722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ++HCount;
13732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
13742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'm':
13752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                timeSkeleton.append(ch);
13762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ++mCount;
13772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
13782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'z':
13792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ++zCount;
13802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                timeSkeleton.append(ch);
13812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
13822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'v':
13832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ++vCount;
13842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                timeSkeleton.append(ch);
13852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
13862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'V':
13872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'Z':
13882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'k':
13892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'K':
13902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'j':
13912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 's':
13922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'S':
13932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              case 'A':
13942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                timeSkeleton.append(ch);
13952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                normalizedTimeSkeleton.append(ch);
13962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
13972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
13982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
13992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
14002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* generate normalized form for date*/
14012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( yCount != 0 ) {
14022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (i = 0; i < yCount; i++) {
14032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                normalizedDateSkeleton.append('y');
14042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
14052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
14062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( MCount != 0 ) {
14072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( MCount < 3 ) {
14082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                normalizedDateSkeleton.append('M');
14092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
14102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for ( i = 0; i < MCount && i < 5; ++i ) {
14112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                     normalizedDateSkeleton.append('M');
14122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
14132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
14142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
14152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( ECount != 0 ) {
14162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( ECount <= 3 ) {
14172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                normalizedDateSkeleton.append('E');
14182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
14192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for ( i = 0; i < ECount && i < 5; ++i ) {
14202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                     normalizedDateSkeleton.append('E');
14212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
14222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
14232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
14242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( dCount != 0 ) {
14252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            normalizedDateSkeleton.append('d');
14262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
14272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
14282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* generate normalized form for time */
14292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( HCount != 0 ) {
14302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            normalizedTimeSkeleton.append('H');
14312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
14322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        else if ( hCount != 0 ) {
14332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            normalizedTimeSkeleton.append('h');
14342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
14352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( mCount != 0 ) {
14362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            normalizedTimeSkeleton.append('m');
14372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
14382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( zCount != 0 ) {
14392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            normalizedTimeSkeleton.append('z');
14402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
14412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( vCount != 0 ) {
14422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            normalizedTimeSkeleton.append('v');
14432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
14442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
14452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
14462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
14472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
14482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
14492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Generate date or time interval pattern from resource.
14502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
14512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * It needs to handle the following:
14522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 1. need to adjust field width.
14532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    For example, the interval patterns saved in DateIntervalInfo
14542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    includes "dMMMy", but not "dMMMMy".
14552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    Need to get interval patterns for dMMMMy from dMMMy.
14562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    Another example, the interval patterns saved in DateIntervalInfo
14572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    includes "hmv", but not "hmz".
14582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    Need to get interval patterns for "hmz' from 'hmv'
14592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
14602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 2. there might be no pattern for 'y' differ for skeleton "Md",
14612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    in order to get interval patterns for 'y' differ,
14622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *    need to look for it from skeleton 'yMd'
14632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
14642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param dateSkeleton   normalized date skeleton
14652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param timeSkeleton   normalized time skeleton
14662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param intervalPatterns interval patterns
14672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return whether there is interval patterns for the skeleton.
14682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         true if there is, false otherwise
14692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
14702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private boolean genSeparateDateTimePtn(String dateSkeleton,
14712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                           String timeSkeleton,
14722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                           Map<String, PatternInfo> intervalPatterns,
14732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                           DateTimePatternGenerator dtpng)
14742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
14752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String skeleton;
14762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // if both date and time skeleton present,
14772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // the final interval pattern might include time interval patterns
14782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // ( when, am_pm, hour, minute, second differ ),
14792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // but not date interval patterns ( when year, month, day differ ).
14802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // For year/month/day differ, it falls back to fall-back pattern.
14812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( timeSkeleton.length() != 0  ) {
14822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            skeleton = timeSkeleton;
14832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
14842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            skeleton = dateSkeleton;
14852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
14862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
14872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* interval patterns for skeleton "dMMMy" (but not "dMMMMy")
14882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * are defined in resource,
14892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * interval patterns for skeleton "dMMMMy" are calculated by
14902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * 1. get the best match skeleton for "dMMMMy", which is "dMMMy"
14912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * 2. get the interval patterns for "dMMMy",
14922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * 3. extend "MMM" to "MMMM" in above interval patterns for "dMMMMy"
14932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * getBestSkeleton() is step 1.
14942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
14952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // best skeleton, and the difference information
14962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        BestMatchInfo retValue = fInfo.getBestSkeleton(skeleton);
14972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String bestSkeleton = retValue.bestMatchSkeleton;
14982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int differenceInfo =  retValue.bestMatchDistanceInfo;
14992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
15002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Set patterns for fallback use, need to do this
15012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // before returning if differenceInfo == -1
15022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (dateSkeleton.length() != 0  ) {
15032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            fDatePattern = dtpng.getBestPattern(dateSkeleton);
15042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
15052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (timeSkeleton.length() != 0  ) {
15062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            fTimePattern = dtpng.getBestPattern(timeSkeleton);
15072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
15082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
15092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // difference:
15102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // 0 means the best matched skeleton is the same as input skeleton
15112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // 1 means the fields are the same, but field width are different
15122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // 2 means the only difference between fields are v/z,
15132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // -1 means there are other fields difference
15142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // (this will happen, for instance, if the supplied skeleton has seconds,
15152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //  but no skeletons in the intervalFormats data do)
15162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( differenceInfo == -1 ) {
15172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // skeleton has different fields, not only  v/z difference
15182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return false;
15192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
15202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
15212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( timeSkeleton.length() == 0 ) {
15222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // only has date skeleton
15232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            genIntervalPattern(Calendar.DATE, skeleton, bestSkeleton, differenceInfo, intervalPatterns);
15242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            SkeletonAndItsBestMatch skeletons = genIntervalPattern(
15252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                  Calendar.MONTH, skeleton,
15262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                  bestSkeleton, differenceInfo,
15272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                  intervalPatterns);
15282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( skeletons != null ) {
15292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                bestSkeleton = skeletons.skeleton;
15302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                skeleton = skeletons.bestMatchSkeleton;
15312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
15322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            genIntervalPattern(Calendar.YEAR, skeleton, bestSkeleton, differenceInfo, intervalPatterns);
15332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
15342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            genIntervalPattern(Calendar.MINUTE, skeleton, bestSkeleton, differenceInfo, intervalPatterns);
15352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            genIntervalPattern(Calendar.HOUR, skeleton, bestSkeleton, differenceInfo, intervalPatterns);
15362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            genIntervalPattern(Calendar.AM_PM, skeleton, bestSkeleton, differenceInfo, intervalPatterns);
15372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
15382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return true;
15392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
15402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
15412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
15422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
15432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
15442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
15452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Generate interval pattern from existing resource
15462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
15472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * It not only save the interval patterns,
15482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * but also return the skeleton and its best match skeleton.
15492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
15502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param field           largest different calendar field
15512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param skeleton        skeleton
15522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param bestSkeleton    the best match skeleton which has interval pattern
15532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                        defined in resource
15542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param differenceInfo  the difference between skeleton and best skeleton
15552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         0 means the best matched skeleton is the same as input skeleton
15562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         1 means the fields are the same, but field width are different
15572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *         2 means the only difference between fields are v/z,
15582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *        -1 means there are other fields difference
15592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
15602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param intervalPatterns interval patterns
15612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
15622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return  an extended skeleton or extended best skeleton if applicable.
15632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *          null otherwise.
15642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
15652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private SkeletonAndItsBestMatch genIntervalPattern(
15662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   int field, String skeleton, String bestSkeleton,
15672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                   int differenceInfo, Map<String, PatternInfo> intervalPatterns) {
15682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        SkeletonAndItsBestMatch retValue = null;
15692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        PatternInfo pattern = fInfo.getIntervalPattern(
15702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                           bestSkeleton, field);
15712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( pattern == null ) {
15722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // single date
15732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( SimpleDateFormat.isFieldUnitIgnored(bestSkeleton, field) ) {
15742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                PatternInfo ptnInfo =
15752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    new PatternInfo(fDateFormat.toPattern(),
15762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                     null,
15772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                     fInfo.getDefaultOrder());
15782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                intervalPatterns.put(DateIntervalInfo.
15792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    CALENDAR_FIELD_TO_PATTERN_LETTER[field], ptnInfo);
15802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return null;
15812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
15822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
15832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // for 24 hour system, interval patterns in resource file
15842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // might not include pattern when am_pm differ,
15852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // which should be the same as hour differ.
15862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // add it here for simplicity
15872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( field == Calendar.AM_PM ) {
15882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 pattern = fInfo.getIntervalPattern(bestSkeleton,
15892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                                         Calendar.HOUR);
15902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 if ( pattern != null ) {
15912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                      // share
15922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                      intervalPatterns.put(DateIntervalInfo.
15932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                          CALENDAR_FIELD_TO_PATTERN_LETTER[field],
15942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                          pattern);
15952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 }
15962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                 return null;
15972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
15982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // else, looking for pattern when 'y' differ for 'dMMMM' skeleton,
15992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // first, get best match pattern "MMMd",
16002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // since there is no pattern for 'y' differs for skeleton 'MMMd',
16012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // need to look for it from skeleton 'yMMMd',
16022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // if found, adjust field width in interval pattern from
16032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // "MMM" to "MMMM".
16042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String fieldLetter =
16052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[field];
16062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            bestSkeleton = fieldLetter + bestSkeleton;
16072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            skeleton = fieldLetter + skeleton;
16082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // for example, looking for patterns when 'y' differ for
16092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // skeleton "MMMM".
16102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            pattern = fInfo.getIntervalPattern(bestSkeleton, field);
16112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( pattern == null && differenceInfo == 0 ) {
16122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // if there is no skeleton "yMMMM" defined,
16132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // look for the best match skeleton, for example: "yMMM"
16142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                BestMatchInfo tmpRetValue = fInfo.getBestSkeleton(skeleton);
16152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                String tmpBestSkeleton = tmpRetValue.bestMatchSkeleton;
16162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                differenceInfo =  tmpRetValue.bestMatchDistanceInfo;
16172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ( tmpBestSkeleton.length() != 0 && differenceInfo != -1 ) {
16182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    pattern = fInfo.getIntervalPattern(tmpBestSkeleton, field);
16192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    bestSkeleton = tmpBestSkeleton;
16202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
16212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
16222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( pattern != null ) {
16232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                retValue = new SkeletonAndItsBestMatch(skeleton, bestSkeleton);
16242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
16252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
16262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( pattern != null ) {
16272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( differenceInfo != 0 ) {
16282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                String part1 = adjustFieldWidth(skeleton, bestSkeleton,
16292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                   pattern.getFirstPart(), differenceInfo);
16302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                String part2 = adjustFieldWidth(skeleton, bestSkeleton,
16312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                   pattern.getSecondPart(), differenceInfo);
16322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                pattern =  new PatternInfo(part1, part2,
16332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                           pattern.firstDateInPtnIsLaterDate());
16342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
16352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // pattern is immutable, no need to clone;
16362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // pattern = (PatternInfo)pattern.clone();
16372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
16382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            intervalPatterns.put(
16392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[field], pattern);
16402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
16412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return retValue;
16422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
16432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
16452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Adjust field width in best match interval pattern to match
16462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the field width in input skeleton.
16472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
16482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * TODO (xji) make a general solution
16492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The adjusting rule can be:
16502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 1. always adjust
16512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 2. never adjust
16522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 3. default adjust, which means adjust according to the following rules
16532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 3.1 always adjust string, such as MMM and MMMM
16542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 3.2 never adjust between string and numeric, such as MM and MMM
16552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 3.3 always adjust year
16562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 3.4 do not adjust 'd', 'h', or 'm' if h presents
16572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * 3.5 do not adjust 'M' if it is numeric(?)
16582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
16592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Since date interval format is well-formed format,
16602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * date and time skeletons are normalized previously,
16612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * till this stage, the adjust here is only "adjust strings, such as MMM
16622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * and MMMM, EEE and EEEE.
16632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
16642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param inputSkeleton            the input skeleton
16652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param bestMatchSkeleton        the best match skeleton
16662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param bestMatchIntervalpattern the best match interval pattern
16672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param differenceInfo           the difference between 2 skeletons
16682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                                 1 means only field width differs
16692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *                                 2 means v/z exchange
16702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return the adjusted interval pattern
16712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
16722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static String adjustFieldWidth(String inputSkeleton,
16732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    String bestMatchSkeleton,
16742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    String bestMatchIntervalPattern,
16752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                    int differenceInfo ) {
16762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( bestMatchIntervalPattern == null ) {
16782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return null; // the 2nd part could be null
16792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
16802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int[] inputSkeletonFieldWidth = new int[58];
16812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int[] bestMatchSkeletonFieldWidth = new int[58];
16822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /* initialize as following
16842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        {
16852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //       A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
16862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            0, 0, 0, 0, 0,  0, 0,  0,  0, 0, 0, 0, 0,  0, 0, 0,
16872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //   P   Q   R   S   T   U   V   W   X   Y   Z
16882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            0, 0, 0, 0, 0,  0, 0,  0,  0, 0, 0, 0, 0,  0, 0, 0,
16892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //       a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
16902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            0, 0, 0, 0, 0,  0, 0,  0,  0, 0, 0, 0, 0,  0, 0, 0,
16912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        //   p   q   r   s   t   u   v   w   x   y   z
16922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            0, 0, 0, 0, 0,  0, 0,  0,  0, 0, 0, 0, 0,  0, 0, 0,
16932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        };
16942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        */
16952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
16972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        DateIntervalInfo.parseSkeleton(inputSkeleton, inputSkeletonFieldWidth);
16982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        DateIntervalInfo.parseSkeleton(bestMatchSkeleton, bestMatchSkeletonFieldWidth);
16992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( differenceInfo == 2 ) {
17002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            bestMatchIntervalPattern = bestMatchIntervalPattern.replace('v', 'z');
17012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
17022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        StringBuilder adjustedPtn = new StringBuilder(bestMatchIntervalPattern);
17042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean inQuote = false;
17062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        char prevCh = 0;
17072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int count = 0;
17082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int PATTERN_CHAR_BASE = 0x41;
17102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // loop through the pattern string character by character
17122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int adjustedPtnLength = adjustedPtn.length();
17132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = 0; i < adjustedPtnLength; ++i) {
17142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            char ch = adjustedPtn.charAt(i);
17152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (ch != prevCh && count > 0) {
17162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // check the repeativeness of pattern letter
17172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                char skeletonChar = prevCh;
17182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ( skeletonChar == 'L' ) {
17192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // for skeleton "M+", the pattern is "...L..."
17202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    skeletonChar = 'M';
17212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
17222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int fieldCount = bestMatchSkeletonFieldWidth[skeletonChar - PATTERN_CHAR_BASE];
17232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int inputFieldCount = inputSkeletonFieldWidth[skeletonChar - PATTERN_CHAR_BASE];
17242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ( fieldCount == count && inputFieldCount > fieldCount ) {
17252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    count = inputFieldCount - fieldCount;
17262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    for ( int j = 0; j < count; ++j ) {
17272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        adjustedPtn.insert(i, prevCh);
17282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
17292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    i += count;
17302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    adjustedPtnLength += count;
17312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
17322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                count = 0;
17332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
17342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (ch == '\'') {
17352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Consecutive single quotes are a single quote literal,
17362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // either outside of quotes or between quotes
17372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if ((i+1) < adjustedPtn.length() && adjustedPtn.charAt(i+1) == '\'') {
17382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ++i;
17392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
17402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    inQuote = ! inQuote;
17412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
17422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
17432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
17442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
17452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // ch is a date-time pattern character
17462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                prevCh = ch;
17472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ++count;
17482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
17492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
17502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( count > 0 ) {
17512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // last item
17522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // check the repeativeness of pattern letter
17532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            char skeletonChar = prevCh;
17542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( skeletonChar == 'L' ) {
17552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // for skeleton "M+", the pattern is "...L..."
17562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                skeletonChar = 'M';
17572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
17582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int fieldCount = bestMatchSkeletonFieldWidth[skeletonChar - PATTERN_CHAR_BASE];
17592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int inputFieldCount = inputSkeletonFieldWidth[skeletonChar - PATTERN_CHAR_BASE];
17602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ( fieldCount == count && inputFieldCount > fieldCount ) {
17612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                count = inputFieldCount - fieldCount;
17622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                for ( int j = 0; j < count; ++j ) {
17632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    adjustedPtn.append(prevCh);
17642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
17652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
17662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
17672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return adjustedPtn.toString();
17682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
17692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
17722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Concat a single date pattern with a time interval pattern,
17732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * set it into the intervalPatterns, while field is time field.
17742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * This is used to handle time interval patterns on skeleton with
17752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * both time and date. Present the date followed by
17762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * the range expression for the time.
17772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param dtfmt                  date and time format
17782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param datePattern            date pattern
17792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param field                  time calendar field: AM_PM, HOUR, MINUTE
17802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param intervalPatterns       interval patterns
17812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
17822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void concatSingleDate2TimeInterval(String dtfmt,
17832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                               String datePattern,
17842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                               int field,
17852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                               Map<String, PatternInfo> intervalPatterns)
17862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
17872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
17882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        PatternInfo  timeItvPtnInfo =
17892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            intervalPatterns.get(DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[field]);
17902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ( timeItvPtnInfo != null ) {
17912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String timeIntervalPattern = timeItvPtnInfo.getFirstPart() +
17922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                         timeItvPtnInfo.getSecondPart();
17932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            String pattern = MessageFormat.format(dtfmt, new Object[]
17942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                         {timeIntervalPattern, datePattern});
17952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            timeItvPtnInfo = DateIntervalInfo.genPatternInfo(pattern,
17962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                timeItvPtnInfo.firstDateInPtnIsLaterDate());
17972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            intervalPatterns.put(
17982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller              DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[field], timeItvPtnInfo);
17992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
18002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // else: fall back
18012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // it should not happen if the interval format defined is valid
18022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
18032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
18062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * check whether a calendar field present in a skeleton.
18072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param field      calendar field need to check
18082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param skeleton   given skeleton on which to check the calendar field
18092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @return           true if field present in a skeleton.
18102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
18112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static boolean fieldExistsInSkeleton(int field, String skeleton)
18122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    {
18132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        String fieldChar = DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[field];
18142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return ( (skeleton.indexOf(fieldChar) == -1) ? false : true ) ;
18152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
18162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
18192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * readObject.
18202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
18212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void readObject(ObjectInputStream stream)
18222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        throws IOException, ClassNotFoundException {
18232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        stream.defaultReadObject();
18242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        initializePattern(isDateIntervalInfoDefault ? LOCAL_PATTERN_CACHE : null);
18252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
18262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
18272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /**
18282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the internal patterns for the skeleton
18292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @deprecated This API is ICU internal only.
183093cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller     * @hide original deprecated declaration
1831836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller     * @hide draft / provisional / internal are hidden on Android
18322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
18332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    @Deprecated
18342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public Map<String, PatternInfo> getRawPatterns() {
18352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // this is unmodifiable, so ok to return directly
18362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return fIntervalPatterns;
18372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
18382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller}
1839