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