12ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* GENERATED SOURCE. DO NOT MODIFY. */ 2f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// © 2016 and later: Unicode, Inc. and others. 3f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License 42ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* 52ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ******************************************************************************* 61c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Copyright (C) 2008-2016, International Business Machines Corporation and 71c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * others. All Rights Reserved. 82ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ******************************************************************************* 92ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpackage android.icu.text; 122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.io.Serializable; 142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.HashMap; 152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.HashSet; 162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.LinkedHashMap; 172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.LinkedHashSet; 182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Locale; 192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Map; 202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Map.Entry; 212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.MissingResourceException; 222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Set; 232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.ICUCache; 251c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubertimport android.icu.impl.ICUData; 262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.ICUResourceBundle; 272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.SimpleCache; 281c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubertimport android.icu.impl.UResource; 291c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubertimport android.icu.impl.UResource.Key; 301c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubertimport android.icu.impl.UResource.Value; 312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.Utility; 322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.Calendar; 332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.Freezable; 342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.ICUCloneNotSupportedException; 351c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubertimport android.icu.util.ICUException; 362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.ULocale; 372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.UResourceBundle; 382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/** 402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * DateIntervalInfo is a public class for encapsulating localizable 412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * date time interval patterns. It is used by DateIntervalFormat. 422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P> 442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For most users, ordinary use of DateIntervalFormat does not need to create 452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * DateIntervalInfo object directly. 462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * DateIntervalFormat will take care of it when creating a date interval 472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * formatter when user pass in skeleton and locale. 482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P> 502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For power users, who want to create their own date interval patterns, 512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * or want to re-set date interval patterns, they could do so by 525cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * directly creating DateIntervalInfo and manipulating it. 532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P> 552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Logically, the interval patterns are mappings 562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * from (skeleton, the_largest_different_calendar_field) 572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * to (date_interval_pattern). 582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P> 601c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * A skeleton 612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <ol> 622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li> 631c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * only keeps the field pattern letter and ignores all other parts 642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * in a pattern, such as space, punctuations, and string literals. 652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li> 661c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * hides the order of fields. 672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <li> 682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * might hide a field's pattern letter length. 692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 701c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * For those non-digit calendar fields, the pattern letter length is 711c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * important, such as MMM, MMMM, and MMMMM; EEE and EEEE, 722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and the field's pattern letter length is honored. 731c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * 741c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * For the digit calendar fields, such as M or MM, d or dd, yy or yyyy, 751c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * the field pattern length is ignored and the best match, which is defined 762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * in date time patterns, will be returned without honor the field pattern 772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * letter length in skeleton. 782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </ol> 792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P> 812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The calendar fields we support for interval formatting are: 822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * year, month, date, day-of-week, am-pm, hour, hour-of-day, minute, and 832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * second (though we do not currently have specific intervalFormat data for 841c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * skeletons with seconds). 852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Those calendar fields can be defined in the following order: 8608ae9f2909b2ec37f755dac4372553437e9d7cf6Paul Duffin * year > month > date > am-pm > hour > minute > second 871c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * 882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * The largest different calendar fields between 2 calendars is the 892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * first different calendar field in above order. 902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 911c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * For example: the largest different calendar fields between "Jan 10, 2007" 922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and "Feb 20, 2008" is year. 931c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * 942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P> 952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * There is a set of pre-defined static skeleton strings. 962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * There are pre-defined interval patterns for those pre-defined skeletons 972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * in locales' resource files. 982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For example, for a skeleton YEAR_ABBR_MONTH_DAY, which is "yMMMd", 991c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * in en_US, if the largest different calendar field between date1 and date2 1001c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * is "year", the date interval pattern is "MMM d, yyyy - MMM d, yyyy", 1012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * such as "Jan 10, 2007 - Jan 10, 2008". 1022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If the largest different calendar field between date1 and date2 is "month", 1032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the date interval pattern is "MMM d - MMM d, yyyy", 1042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * such as "Jan 10 - Feb 10, 2007". 1052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * If the largest different calendar field between date1 and date2 is "day", 1062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the date interval pattern is ""MMM d-d, yyyy", such as "Jan 10-20, 2007". 1072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 1081c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * For date skeleton, the interval patterns when year, or month, or date is 1092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * different are defined in resource files. 1102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For time skeleton, the interval patterns when am/pm, or hour, or minute is 1112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * different are defined in resource files. 1122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 1132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 1142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P> 1152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * There are 2 dates in interval pattern. For most locales, the first date 1162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * in an interval pattern is the earlier date. There might be a locale in which 1172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the first date in an interval pattern is the later date. 1182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * We use fallback format for the default order for the locale. 1192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For example, if the fallback format is "{0} - {1}", it means 1202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the first date in the interval pattern for this locale is earlier date. 1211c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * If the fallback format is "{1} - {0}", it means the first date is the 1222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * later date. 1232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For a particular interval pattern, the default order can be overriden 1242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * by prefixing "latestFirst:" or "earliestFirst:" to the interval pattern. 1252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For example, if the fallback format is "{0}-{1}", 1261c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * but for skeleton "yMMMd", the interval pattern when day is different is 1272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * "latestFirst:d-d MMM yy", it means by default, the first date in interval 1282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * pattern is the earlier date. But for skeleton "yMMMd", when day is different, 1292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the first date in "d-d MMM yy" is the later date. 1301c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * 1312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P> 1321c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * The recommended way to create a DateIntervalFormat object is to pass in 1331c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * the locale. 1341c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * By using a Locale parameter, the DateIntervalFormat object is 1351c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * initialized with the pre-defined interval patterns for a given or 1362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * default locale. 1372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P> 1381c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Users can also create DateIntervalFormat object 1392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * by supplying their own interval patterns. 1402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * It provides flexibility for power usage. 1412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 1422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P> 1432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * After a DateIntervalInfo object is created, clients may modify 1442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the interval patterns using setIntervalPattern function as so desired. 1451c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Currently, users can only set interval patterns when the following 1461c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * calendar fields are different: ERA, YEAR, MONTH, DATE, DAY_OF_MONTH, 1472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * DAY_OF_WEEK, AM_PM, HOUR, HOUR_OF_DAY, MINUTE and SECOND. 1482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Interval patterns when other calendar fields are different is not supported. 1492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P> 1501c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * DateIntervalInfo objects are cloneable. 1511c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * When clients obtain a DateIntervalInfo object, 1522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * they can feel free to modify it as necessary. 1532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P> 1541c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * DateIntervalInfo are not expected to be subclassed. 1551c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Data for a calendar is loaded out of resource bundles. 1562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Through ICU 4.4, date interval patterns are only supported in the Gregoria 1571c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * calendar; non-Gregorian calendars are supported from ICU 4.4.1. 1582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpublic class DateIntervalInfo implements Cloneable, Freezable<DateIntervalInfo>, Serializable { 1612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* Save the interval pattern information. 1632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Interval pattern consists of 2 single date patterns and the separator. 1642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For example, interval pattern "MMM d - MMM d, yyyy" consists 1652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * a single date pattern "MMM d", another single date pattern "MMM d, yyyy", 1662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and a separator "-". 1671c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Also, the first date appears in an interval pattern could be 1682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the earlier date or the later date. 1692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * And such information is saved in the interval pattern as well. 1702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller static final int currentSerialVersion = 1; 1722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * PatternInfo class saves the first and second part of interval pattern, 1752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and whether the interval pattern is earlier date first. 1762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public static final class PatternInfo implements Cloneable, Serializable { 1782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller static final int currentSerialVersion = 1; 1792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static final long serialVersionUID = 1; 1802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private final String fIntervalPatternFirstPart; 1812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private final String fIntervalPatternSecondPart; 1822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* 1832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Whether the first date in interval pattern is later date or not. 1842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Fallback format set the default ordering. 1851c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * And for a particular interval pattern, the order can be 1861c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * overriden by prefixing the interval pattern with "latestFirst:" or 1872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * "earliestFirst:" 1882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For example, given 2 date, Jan 10, 2007 to Feb 10, 2007. 1891c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * if the fallback format is "{0} - {1}", 1902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and the pattern is "d MMM - d MMM yyyy", the interval format is 1912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * "10 Jan - 10 Feb, 2007". 1921c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * If the pattern is "latestFirst:d MMM - d MMM yyyy", 1932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the interval format is "10 Feb - 10 Jan, 2007" 1942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private final boolean fFirstDateInPtnIsLaterDate; 1962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 1972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 1985cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * Constructs a <code>PatternInfo</code> object. 1995cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * @param firstPart The first part of interval pattern. 2005cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * @param secondPart The second part of interval pattern. 2015cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * @param firstDateInPtnIsLaterDate Whether the first date in interval patter is later date or not. 2022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public PatternInfo(String firstPart, String secondPart, 2042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller boolean firstDateInPtnIsLaterDate) { 2052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fIntervalPatternFirstPart = firstPart; 2062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fIntervalPatternSecondPart = secondPart; 2072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fFirstDateInPtnIsLaterDate = firstDateInPtnIsLaterDate; 2082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2115cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * Returns the first part of interval pattern. 2125cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * @return The first part of interval pattern. 2132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String getFirstPart() { 2152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return fIntervalPatternFirstPart; 2162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2195cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * Returns the second part of interval pattern. 2205cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * @return The second part of interval pattern. 2212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String getSecondPart() { 2232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return fIntervalPatternSecondPart; 2242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2275cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * Returns whether the first date in interval patter is later date or not. 2285cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * @return Whether the first date in interval patter is later date or not. 2292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public boolean firstDateInPtnIsLaterDate() { 2312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return fFirstDateInPtnIsLaterDate; 2322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2355cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * Compares the specified object with this <code>PatternInfo</code> for equality. 2365cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * @param a The object to be compared. 2375cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * @return <code>true</code> if the specified object is equal to this <code>PatternInfo</code>. 2382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 239f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 2402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public boolean equals(Object a) { 241f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert if (a instanceof PatternInfo) { 2422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller PatternInfo patternInfo = (PatternInfo)a; 2431c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert return Utility.objectEquals(fIntervalPatternFirstPart, patternInfo.fIntervalPatternFirstPart) && 244f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert Utility.objectEquals(fIntervalPatternSecondPart, patternInfo.fIntervalPatternSecondPart) && 2452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fFirstDateInPtnIsLaterDate == patternInfo.fFirstDateInPtnIsLaterDate; 2462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return false; 2482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2515cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * Returns the hash code of this <code>PatternInfo</code>. 2525cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * @return A hash code value for this object. 2532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 254f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 2552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public int hashCode() { 2562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int hash = fIntervalPatternFirstPart != null ? fIntervalPatternFirstPart.hashCode() : 0; 2572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (fIntervalPatternSecondPart != null) { 2582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller hash ^= fIntervalPatternSecondPart.hashCode(); 2592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (fFirstDateInPtnIsLaterDate) { 2612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller hash ^= -1; 2622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return hash; 2642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 2672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * {@inheritDoc} 2682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @deprecated This API is ICU internal only. 269836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide draft / provisional / internal are hidden on Android 2702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 2712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Deprecated 2722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Override 2732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String toString() { 2742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return "{first=«" + fIntervalPatternFirstPart + "», second=«" + fIntervalPatternSecondPart + "», reversed:" + fFirstDateInPtnIsLaterDate + "}"; 2752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 2772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2781c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert // Following is package protected since 2792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // it is shared with DateIntervalFormat. 2801c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert static final String[] CALENDAR_FIELD_TO_PATTERN_LETTER = 2812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller { 2822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller "G", "y", "M", 2831c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert "w", "W", "d", 2842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller "D", "E", "F", 2852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller "a", "h", "H", 2862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller "m", "s", "S", // MINUTE, SECOND, MILLISECOND 2872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller "z", " ", "Y", // ZONE_OFFSET, DST_OFFSET, YEAR_WOY 2882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller "e", "u", "g", // DOW_LOCAL, EXTENDED_YEAR, JULIAN_DAY 2892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller "A", " ", " ", // MILLISECONDS_IN_DAY, IS_LEAP_MONTH. 2902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller }; 2912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static final long serialVersionUID = 1; 2941c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert private static final int MINIMUM_SUPPORTED_CALENDAR_FIELD = 2952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Calendar.SECOND; 2962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller //private static boolean DEBUG = true; 2972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 2981c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert private static String CALENDAR_KEY = "calendar"; 2991c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert private static String INTERVAL_FORMATS_KEY = "intervalFormats"; 3002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static String FALLBACK_STRING = "fallback"; 3012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static String LATEST_FIRST_PREFIX = "latestFirst:"; 3022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static String EARLIEST_FIRST_PREFIX = "earliestFirst:"; 3032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // DateIntervalInfo cache 3052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private final static ICUCache<String, DateIntervalInfo> DIICACHE = new SimpleCache<String, DateIntervalInfo>(); 3062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // default interval pattern on the skeleton, {0} - {1} 3092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private String fFallbackIntervalPattern; 3102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // default order 3112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private boolean fFirstDateInPtnIsLaterDate = false; 3122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // HashMap( skeleton, HashMap(largest_different_field, pattern) ) 3142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private Map<String, Map<String, PatternInfo>> fIntervalPatterns = null; 3152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private transient volatile boolean frozen = false; 3171c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 3182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // If true, fIntervalPatterns should not be modified in-place because it 3192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // is shared with other objects. Unlike frozen which is always true once 3202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // set to true, this field can go from true to false as long as frozen is 3212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // false. 3222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private transient boolean fIntervalPatternsReadOnly = false; 3232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 3262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Create empty instance. 3272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * It does not initialize any interval patterns except 3282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * that it initialize default fall-back pattern as "{0} - {1}", 3292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * which can be reset by setFallbackIntervalPattern(). 3302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 3311c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * It should be followed by setFallbackIntervalPattern() and 3321c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * setIntervalPattern(), 3332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and is recommended to be used only for power users who 3342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * wants to create their own interval patterns and use them to create 3352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * date interval formatter. 3362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @deprecated This API is ICU internal only. 33793cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller * @hide original deprecated declaration 338836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide draft / provisional / internal are hidden on Android 3392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 3402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Deprecated 3411c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert public DateIntervalInfo() 3422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller { 3432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fIntervalPatterns = new HashMap<String, Map<String, PatternInfo>>(); 3442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fFallbackIntervalPattern = "{0} \u2013 {1}"; 3452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3481c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert /** 3492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Construct DateIntervalInfo for the given locale, 3501c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * @param locale the interval patterns are loaded from the appropriate 3512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * calendar data (specified calendar or default calendar) 3522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * in this locale. 3532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 3541c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert public DateIntervalInfo(ULocale locale) 3552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller { 3562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller initializeData(locale); 3572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3601c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert /** 3617241d93e30f4c7c527c019cd6ca3a791ca22d9b2Fredrik Roubert * Construct DateIntervalInfo for the given {@link java.util.Locale}. 3621c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * @param locale the interval patterns are loaded from the appropriate 3632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * calendar data (specified calendar or default calendar) 3642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * in this locale. 3652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 3661c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert public DateIntervalInfo(Locale locale) 3672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller { 3682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller this(ULocale.forLocale(locale)); 3692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* 3722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Initialize the DateIntervalInfo from locale 3732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param locale the given locale. 3742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 3752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private void initializeData(ULocale locale) 3762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller { 3772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String key = locale.toString(); 3782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller DateIntervalInfo dii = DIICACHE.get(key); 3792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( dii == null ) { 3802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // initialize data from scratch 3812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller setup(locale); 3822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Marking fIntervalPatterns read-only makes cloning cheaper. 3832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fIntervalPatternsReadOnly = true; 3842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // We freeze what goes in the cache without freezing this object. 3852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller DIICACHE.put(key, ((DateIntervalInfo) clone()).freeze()); 3862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 3872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller initializeFromReadOnlyPatterns(dii); 3882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 3902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3911c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 3922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 3932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 3942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Initialize this object 3952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param dii must have read-only fIntervalPatterns. 3962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 3972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private void initializeFromReadOnlyPatterns(DateIntervalInfo dii) { 3982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fFallbackIntervalPattern = dii.fFallbackIntervalPattern; 3992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fFirstDateInPtnIsLaterDate = dii.fFirstDateInPtnIsLaterDate; 4002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fIntervalPatterns = dii.fIntervalPatterns; 4012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fIntervalPatternsReadOnly = true; 4022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 4032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 4051c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 4061c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert /** 4071c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Sink for enumerating all of the date interval skeletons. 4081c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert */ 409f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert private static final class DateIntervalSink extends UResource.Sink { 4101c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 4111c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert /** 4121c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Accepted pattern letters: 4131c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Calendar.YEAR 4141c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Calendar.MONTH 4151c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Calendar.DATE 4161c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Calendar.AM_PM 4171c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Calendar.HOUR 4181c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Calendar.HOUR_OF_DAY 4191c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Calendar.MINUTE 4201c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Calendar.SECOND 4211c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert */ 4221c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert private static final String ACCEPTED_PATTERN_LETTERS = "yMdahHms"; 4231c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 4241c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert // Output data 4251c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert DateIntervalInfo dateIntervalInfo; 4261c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 4271c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert // Alias handling 4281c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert String nextCalendarType; 4291c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 4301c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert // Constructor 4311c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert public DateIntervalSink(DateIntervalInfo dateIntervalInfo) { 4321c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert this.dateIntervalInfo = dateIntervalInfo; 4331c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert } 4341c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 4351c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert @Override 436f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert public void put(Key key, Value value, boolean noFallback) { 437f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // Iterate over all the calendar entries and only pick the 'intervalFormats' table. 438f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert UResource.Table dateIntervalData = value.getTable(); 439f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert for (int i = 0; dateIntervalData.getKeyAndValue(i, key, value); i++) { 440f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert if (!key.contentEquals(INTERVAL_FORMATS_KEY)) { 441f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert continue; 442f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } 4431c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 444f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // Handle aliases and tables. Ignore the rest. 445f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert if (value.getType() == ICUResourceBundle.ALIAS) { 446f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // Get the calendar type from the alias path. 447f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert nextCalendarType = getCalendarTypeFromPath(value.getAliasString()); 448f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert break; 449f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 450f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } else if (value.getType() == ICUResourceBundle.TABLE) { 451f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // Iterate over all the skeletons in the 'intervalFormat' table. 452f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert UResource.Table skeletonData = value.getTable(); 453f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert for (int j = 0; skeletonData.getKeyAndValue(j, key, value); j++) { 454f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert if (value.getType() == ICUResourceBundle.TABLE) { 455f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // Process the skeleton 456f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert processSkeletonTable(key, value); 457f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } 458f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } 459f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert break; 460f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } 461f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } 4621c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert } 4631c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 464f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert /** Processes the patterns for a skeleton table. */ 465f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert public void processSkeletonTable(Key key, Value value) { 466f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // Iterate over all the patterns in the current skeleton table 467f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert String currentSkeleton = key.toString(); 468f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert UResource.Table patternData = value.getTable(); 469f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert for (int k = 0; patternData.getKeyAndValue(k, key, value); k++) { 470f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert if (value.getType() == ICUResourceBundle.STRING) { 471f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // Process the key 472f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert CharSequence patternLetter = validateAndProcessPatternLetter(key); 473f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 474f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // If the calendar field has a valid value 475f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert if (patternLetter != null) { 476f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // Get the largest different calendar unit 477f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert String lrgDiffCalUnit = patternLetter.toString(); 478f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 479f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // Set the interval pattern 480f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert setIntervalPatternIfAbsent(currentSkeleton, lrgDiffCalUnit, value); 481f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } 482f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } 4831c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert } 4841c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert } 4851c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 4861c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert /** 4871c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Returns and resets the next calendar type. 4881c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * @return Next calendar type 4891c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert */ 4901c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert public String getAndResetNextCalendarType() { 4911c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert String tmpCalendarType = nextCalendarType; 4921c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert nextCalendarType = null; 4931c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert return tmpCalendarType; 4941c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert } 4951c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 496f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // Alias' path prefix and suffix. 4971c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert private static final String DATE_INTERVAL_PATH_PREFIX = 4981c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert "/LOCALE/" + CALENDAR_KEY + "/"; 499f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert private static final String DATE_INTERVAL_PATH_SUFFIX = 5001c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert "/" + INTERVAL_FORMATS_KEY; 5011c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 5021c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert /** 5031c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Extracts the calendar type from the path 5041c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * @param path 5051c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * @return Calendar Type 5061c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert */ 5071c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert private String getCalendarTypeFromPath(String path) { 5081c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert if (path.startsWith(DATE_INTERVAL_PATH_PREFIX) && 509f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert path.endsWith(DATE_INTERVAL_PATH_SUFFIX)) { 5101c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert return path.substring(DATE_INTERVAL_PATH_PREFIX.length(), 511f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert path.length() - DATE_INTERVAL_PATH_SUFFIX.length()); 5121c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert } 5131c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert throw new ICUException("Malformed 'intervalFormat' alias path: " + path); 5141c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert } 515f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 516f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert /** 517f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * Processes the pattern letter 518f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * @param patternLetter 519f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * @return Pattern letter 520f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert */ 521f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert private CharSequence validateAndProcessPatternLetter(CharSequence patternLetter) { 522f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // Check that patternLetter is just one letter 523f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert if (patternLetter.length() != 1) { return null; } 524f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 525f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // Check that the pattern letter is accepted 526f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert char letter = patternLetter.charAt(0); 527f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert if (ACCEPTED_PATTERN_LETTERS.indexOf(letter) < 0) { 528f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert return null; 529f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } 530f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 531f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // Replace 'h' for 'H' 532f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert if (letter == CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.HOUR_OF_DAY].charAt(0)) { 533f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert patternLetter = CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.HOUR]; 534f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } 535f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 536f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert return patternLetter; 537f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } 538f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert 539f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert /** 540f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * Stores the interval pattern for the current skeleton in the internal data structure 541f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * if it's not present. 542f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * @param lrgDiffCalUnit 543f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert * @param intervalPattern 544f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert */ 545f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert private void setIntervalPatternIfAbsent(String currentSkeleton, String lrgDiffCalUnit, Value intervalPattern) { 546f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // Check if the pattern has already been stored on the data structure. 547f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert Map<String, PatternInfo> patternsOfOneSkeleton = 548f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert dateIntervalInfo.fIntervalPatterns.get(currentSkeleton); 549f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert if (patternsOfOneSkeleton == null || !patternsOfOneSkeleton.containsKey(lrgDiffCalUnit)) { 550f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert // Store the pattern 551f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert dateIntervalInfo.setIntervalPatternInternally(currentSkeleton, lrgDiffCalUnit, 552f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert intervalPattern.toString()); 553f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } 554f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert } 5551c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert } 5561c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 5571c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 5582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* 5592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Initialize DateIntervalInfo from calendar data 5602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param calData calendar data 5612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 5621c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert private void setup(ULocale locale) { 5632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int DEFAULT_HASH_SIZE = 19; 5642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fIntervalPatterns = new HashMap<String, Map<String, PatternInfo>>(DEFAULT_HASH_SIZE); 5651c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert // initialize to guard if there is no interval date format defined in 5662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // resource files 5672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fFallbackIntervalPattern = "{0} \u2013 {1}"; 5681c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 5692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller try { 5702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Get the correct calendar type 5712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String calendarTypeToUse = locale.getKeywordValue("calendar"); 5722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( calendarTypeToUse == null ) { 5731c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert String[] preferredCalendarTypes = 5741c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert Calendar.getKeywordValuesForLocale("calendar", locale, true); 5752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller calendarTypeToUse = preferredCalendarTypes[0]; // the most preferred calendar 5762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( calendarTypeToUse == null ) { 5782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller calendarTypeToUse = "gregorian"; // fallback 5792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 5811c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert // Instantiate the sink to process the data and the resource bundle 5821c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert DateIntervalSink sink = new DateIntervalSink(this); 5831c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert ICUResourceBundle resource = 5841c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUData.ICU_BASE_NAME, locale); 5851c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 5861c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert // Get the fallback pattern 5871c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert String fallbackPattern = resource.getStringWithFallback(CALENDAR_KEY + "/" + calendarTypeToUse 5881c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert + "/" + INTERVAL_FORMATS_KEY + "/" + FALLBACK_STRING); 5891c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert setFallbackIntervalPattern(fallbackPattern); 5901c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 5911c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert // Already loaded calendar types 5921c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert Set<String> loadedCalendarTypes = new HashSet<String>(); 5931c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 5941c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert while (calendarTypeToUse != null) { 5951c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert // Throw an exception when a loop is detected 5961c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert if (loadedCalendarTypes.contains(calendarTypeToUse)) { 5971c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert throw new ICUException("Loop in calendar type fallback: " + calendarTypeToUse); 5982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 5991c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 6001c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert // Register the calendar type to avoid loops 6011c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert loadedCalendarTypes.add(calendarTypeToUse); 6021c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 6031c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert // Get all resources for this calendar type 6041c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert String pathToIntervalFormats = CALENDAR_KEY + "/" + calendarTypeToUse; 605f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert resource.getAllItemsWithFallback(pathToIntervalFormats, sink); 6061c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 6071c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert // Get next calendar type to load if there was an alias pointing at it 6081c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert calendarTypeToUse = sink.getAndResetNextCalendarType(); 6091c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert } 6102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } catch ( MissingResourceException e) { 6111c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert // Will fallback to {data0} - {date1} 6122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* 6172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Split interval patterns into 2 part. 6182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param intervalPattern interval pattern 6192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return the index in interval pattern which split the pattern into 2 part 6202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static int splitPatternInto2Part(String intervalPattern) { 6222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller boolean inQuote = false; 6232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller char prevCh = 0; 6242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int count = 0; 6251c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 6262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* repeatedPattern used to record whether a pattern has already seen. 6272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller It is a pattern applies to first calendar if it is first time seen, 6282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller otherwise, it is a pattern applies to the second calendar 6292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int[] patternRepeated = new int[58]; 6312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int PATTERN_CHAR_BASE = 0x41; 6331c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 6342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* loop through the pattern string character by character looking for 6352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the first repeated pattern letter, which breaks the interval pattern 6361c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * into 2 parts. 6372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 6382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int i; 6392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller boolean foundRepetition = false; 6402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (i = 0; i < intervalPattern.length(); ++i) { 6412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller char ch = intervalPattern.charAt(i); 6421c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 6432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (ch != prevCh && count > 0) { 6442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // check the repeativeness of pattern letter 6452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int repeated = patternRepeated[prevCh - PATTERN_CHAR_BASE]; 6462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( repeated == 0 ) { 6472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller patternRepeated[prevCh - PATTERN_CHAR_BASE] = 1; 6482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 6492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller foundRepetition = true; 6502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break; 6512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller count = 0; 6532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (ch == '\'') { 6552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // Consecutive single quotes are a single quote literal, 6562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // either outside of quotes or between quotes 6571c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert if ((i+1) < intervalPattern.length() && 6582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller intervalPattern.charAt(i+1) == '\'') { 6592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ++i; 6602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 6612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller inQuote = ! inQuote; 6622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6631c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert } 6642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller else if (!inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/) 6652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) { 6661c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert // ch is a date-time pattern character 6672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller prevCh = ch; 6682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ++count; 6692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // check last pattern char, distinguish 6721c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert // "dd MM" ( no repetition ), 6731c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert // "d-d"(last char repeated ), and 6742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // "d-d MM" ( repetition found ) 6752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( count > 0 && foundRepetition == false ) { 6762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( patternRepeated[prevCh - PATTERN_CHAR_BASE] == 0 ) { 6772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller count = 0; 6782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return (i - count); 6812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 6822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 6841c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert /** 6852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Provides a way for client to build interval patterns. 6861c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * User could construct DateIntervalInfo by providing 6872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * a list of skeletons and their patterns. 6882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <P> 6892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * For example: 6902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * <pre> 6912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * DateIntervalInfo dIntervalInfo = new DateIntervalInfo(); 6921c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * dIntervalInfo.setIntervalPattern("yMd", Calendar.YEAR, "'from' yyyy-M-d 'to' yyyy-M-d"); 6932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * dIntervalInfo.setIntervalPattern("yMMMd", Calendar.MONTH, "'from' yyyy MMM d 'to' MMM d"); 6942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * dIntervalInfo.setIntervalPattern("yMMMd", Calendar.DAY, "yyyy MMM d-d"); 6952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * dIntervalInfo.setFallbackIntervalPattern("{0} ~ {1}"); 6962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * </pre> 6972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 6981c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Restriction: 6991c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Currently, users can only set interval patterns when the following 7001c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * calendar fields are different: ERA, YEAR, MONTH, DATE, DAY_OF_MONTH, 7012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * DAY_OF_WEEK, AM_PM, HOUR, HOUR_OF_DAY, MINUTE, and SECOND. 7021c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * Interval patterns when other calendar fields are different are 7032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * not supported. 7042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 7052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param skeleton the skeleton on which interval pattern based 7062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param lrgDiffCalUnit the largest different calendar unit. 7072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param intervalPattern the interval pattern on the largest different 7082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * calendar unit. 7091c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * For example, if lrgDiffCalUnit is 7102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * "year", the interval pattern for en_US when year 7112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * is different could be "'from' yyyy 'to' yyyy". 7121c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * @throws IllegalArgumentException if setting interval pattern on 7132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * a calendar field that is smaller 7141c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * than the MINIMUM_SUPPORTED_CALENDAR_FIELD 7152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @throws UnsupportedOperationException if the object is frozen 7162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 7171c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert public void setIntervalPattern(String skeleton, 7181c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert int lrgDiffCalUnit, 7192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String intervalPattern) 7202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller { 7212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( frozen ) { 7222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new UnsupportedOperationException("no modification is allowed after DII is frozen"); 7232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( lrgDiffCalUnit > MINIMUM_SUPPORTED_CALENDAR_FIELD ) { 7252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new IllegalArgumentException("calendar field is larger than MINIMUM_SUPPORTED_CALENDAR_FIELD"); 7262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (fIntervalPatternsReadOnly) { 7282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fIntervalPatterns = cloneIntervalPatterns(fIntervalPatterns); 7292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fIntervalPatternsReadOnly = false; 7302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller PatternInfo ptnInfo = setIntervalPatternInternally(skeleton, 7321c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert CALENDAR_FIELD_TO_PATTERN_LETTER[lrgDiffCalUnit], 7332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller intervalPattern); 7342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( lrgDiffCalUnit == Calendar.HOUR_OF_DAY ) { 7351c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert setIntervalPattern(skeleton, 7362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.AM_PM], 7372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ptnInfo); 7381c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert setIntervalPattern(skeleton, 7392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.HOUR], 7402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ptnInfo); 7412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else if ( lrgDiffCalUnit == Calendar.DAY_OF_MONTH || 7422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller lrgDiffCalUnit == Calendar.DAY_OF_WEEK ) { 7431c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert setIntervalPattern(skeleton, 7442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.DATE], 7452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ptnInfo); 7462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* Set Interval pattern. 7512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 7521c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * It generates the interval pattern info, 7532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * afer which, not only sets the interval pattern info into the hash map, 7542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * but also returns the interval pattern info to the caller 7552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * so that caller can re-use it. 7562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 7572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param skeleton skeleton on which the interval pattern based 7582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param lrgDiffCalUnit the largest different calendar unit. 7592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param intervalPattern the interval pattern on the largest different 7602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * calendar unit. 7612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return the interval pattern pattern information 7622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 7632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private PatternInfo setIntervalPatternInternally(String skeleton, 7642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String lrgDiffCalUnit, 7652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String intervalPattern) { 7662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Map<String, PatternInfo> patternsOfOneSkeleton = fIntervalPatterns.get(skeleton); 7672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller boolean emptyHash = false; 7682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (patternsOfOneSkeleton == null) { 7692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller patternsOfOneSkeleton = new HashMap<String, PatternInfo>(); 7702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller emptyHash = true; 7712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller boolean order = fFirstDateInPtnIsLaterDate; 7732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // check for "latestFirst:" or "earliestFirst:" prefix 7742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( intervalPattern.startsWith(LATEST_FIRST_PREFIX) ) { 7752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller order = true; 7762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int prefixLength = LATEST_FIRST_PREFIX.length(); 7772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller intervalPattern = intervalPattern.substring(prefixLength, intervalPattern.length()); 7782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else if ( intervalPattern.startsWith(EARLIEST_FIRST_PREFIX) ) { 7792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller order = false; 7802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int earliestFirstLength = EARLIEST_FIRST_PREFIX.length(); 7812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller intervalPattern = intervalPattern.substring(earliestFirstLength, intervalPattern.length()); 7822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller PatternInfo itvPtnInfo = genPatternInfo(intervalPattern, order); 7842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller patternsOfOneSkeleton.put(lrgDiffCalUnit, itvPtnInfo); 7862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( emptyHash == true ) { 7872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fIntervalPatterns.put(skeleton, patternsOfOneSkeleton); 7882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return itvPtnInfo; 7912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 7922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 7942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* Set Interval pattern. 7952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 7962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param skeleton skeleton on which the interval pattern based 7972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param lrgDiffCalUnit the largest different calendar unit. 7981c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * @param ptnInfo interval pattern infomration 7992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 8002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private void setIntervalPattern(String skeleton, 8012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String lrgDiffCalUnit, 8022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller PatternInfo ptnInfo) { 8032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Map<String, PatternInfo> patternsOfOneSkeleton = fIntervalPatterns.get(skeleton); 8042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller patternsOfOneSkeleton.put(lrgDiffCalUnit, ptnInfo); 8052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 8092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Break interval patterns as 2 part and save them into pattern info. 8102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param intervalPattern interval pattern 8112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param laterDateFirst whether the first date in intervalPattern 8122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * is earlier date or later date 8132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return pattern info object 8142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @deprecated This API is ICU internal only. 81593cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller * @hide original deprecated declaration 816836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide draft / provisional / internal are hidden on Android 8172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 8182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Deprecated 8191c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert public static PatternInfo genPatternInfo(String intervalPattern, 8202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller boolean laterDateFirst) { 8212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int splitPoint = splitPatternInto2Part(intervalPattern); 8221c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 8232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String firstPart = intervalPattern.substring(0, splitPoint); 8242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String secondPart = null; 8252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( splitPoint < intervalPattern.length() ) { 8262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller secondPart = intervalPattern.substring(splitPoint, intervalPattern.length()); 8272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return new PatternInfo(firstPart, secondPart, laterDateFirst); 8302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 8342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Get the interval pattern given the largest different calendar field. 8352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param skeleton the skeleton 8362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param field the largest different calendar field 8372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return interval pattern return null if interval pattern is not found. 8381c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * @throws IllegalArgumentException if getting interval pattern on 8392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * a calendar field that is smaller 8401c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * than the MINIMUM_SUPPORTED_CALENDAR_FIELD 8412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 8421c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert public PatternInfo getIntervalPattern(String skeleton, int field) 8432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller { 8442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( field > MINIMUM_SUPPORTED_CALENDAR_FIELD ) { 8452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new IllegalArgumentException("no support for field less than SECOND"); 8462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Map<String, PatternInfo> patternsOfOneSkeleton = fIntervalPatterns.get(skeleton); 8482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( patternsOfOneSkeleton != null ) { 8492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller PatternInfo intervalPattern = patternsOfOneSkeleton. 8502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller get(CALENDAR_FIELD_TO_PATTERN_LETTER[field]); 8512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( intervalPattern != null ) { 8522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return intervalPattern; 8532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return null; 8562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 8612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Get the fallback interval pattern. 8622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return fallback interval pattern 8632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 8642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public String getFallbackIntervalPattern() 8652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller { 8662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return fFallbackIntervalPattern; 8672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 8702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 8712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Re-set the fallback interval pattern. 8722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 8732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * In construction, default fallback pattern is set as "{0} - {1}". 8742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * And constructor taking locale as parameter will set the 8752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * fallback pattern as what defined in the locale resource file. 8762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 8772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * This method provides a way for user to replace the fallback pattern. 8782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 8792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param fallbackPattern fall-back interval pattern. 8802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @throws UnsupportedOperationException if the object is frozen 8811c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * @throws IllegalArgumentException if there is no pattern {0} or 8822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * pattern {1} in fallbakckPattern 8832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 8842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public void setFallbackIntervalPattern(String fallbackPattern) 8852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller { 8862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( frozen ) { 8872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new UnsupportedOperationException("no modification is allowed after DII is frozen"); 8882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int firstPatternIndex = fallbackPattern.indexOf("{0}"); 8902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int secondPatternIndex = fallbackPattern.indexOf("{1}"); 8912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( firstPatternIndex == -1 || secondPatternIndex == -1 ) { 8922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new IllegalArgumentException("no pattern {0} or pattern {1} in fallbackPattern"); 8932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( firstPatternIndex > secondPatternIndex ) { 8952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fFirstDateInPtnIsLaterDate = true; 8962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fFallbackIntervalPattern = fallbackPattern; 8982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 8992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 9022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Get default order -- whether the first date in pattern is later date 9032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * or not. 9042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 9051c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * return default date ordering in interval pattern. TRUE if the first date 9062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * in pattern is later date, FALSE otherwise. 9072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 9082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public boolean getDefaultOrder() 9092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller { 9102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return fFirstDateInPtnIsLaterDate; 9112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 9155cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * Clone this object. 9162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return a copy of the object 9172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 918f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 9191c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert public Object clone() 9202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller { 9212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( frozen ) { 9222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return this; 9232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return cloneUnfrozenDII(); 9252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* 9292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Clone an unfrozen DateIntervalInfo object. 9302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return a copy of the object 9312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 9322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private Object cloneUnfrozenDII() //throws IllegalStateException 9332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller { 9342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller try { 9352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller DateIntervalInfo other = (DateIntervalInfo) super.clone(); 9362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller other.fFallbackIntervalPattern=fFallbackIntervalPattern; 9372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller other.fFirstDateInPtnIsLaterDate = fFirstDateInPtnIsLaterDate; 9382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if (fIntervalPatternsReadOnly) { 9392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller other.fIntervalPatterns = fIntervalPatterns; 9402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller other.fIntervalPatternsReadOnly = true; 9412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 9422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller other.fIntervalPatterns = cloneIntervalPatterns(fIntervalPatterns); 9432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller other.fIntervalPatternsReadOnly = false; 9442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller other.frozen = false; 9462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return other; 9472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } catch ( CloneNotSupportedException e ) { 9482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ///CLOVER:OFF 9492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller throw new ICUCloneNotSupportedException("clone is not supported", e); 9502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ///CLOVER:ON 9512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9531c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 9542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static Map<String, Map<String, PatternInfo>> cloneIntervalPatterns( 9552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Map<String, Map<String, PatternInfo>> patterns) { 9562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Map<String, Map<String, PatternInfo>> result = new HashMap<String, Map<String, PatternInfo>>(); 9572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (Entry<String, Map<String, PatternInfo>> skeletonEntry : patterns.entrySet()) { 9582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String skeleton = skeletonEntry.getKey(); 9592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Map<String, PatternInfo> patternsOfOneSkeleton = skeletonEntry.getValue(); 9602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller Map<String, PatternInfo> oneSetPtn = new HashMap<String, PatternInfo>(); 9612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (Entry<String, PatternInfo> calEntry : patternsOfOneSkeleton.entrySet()) { 9622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String calField = calEntry.getKey(); 9632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller PatternInfo value = calEntry.getValue(); 9642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller oneSetPtn.put(calField, value); 9652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result.put(skeleton, oneSetPtn); 9672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return result; 9692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 9711c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 9721c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 9732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 9745cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * {@inheritDoc} 9752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 976f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 9772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public boolean isFrozen() { 9782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return frozen; 9792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9801c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 9812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 9825cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * {@inheritDoc} 9832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 984f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 9852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public DateIntervalInfo freeze() { 9862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fIntervalPatternsReadOnly = true; 9872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller frozen = true; 9882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return this; 9892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9901c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 9912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 9925cf9d333bc032f332a812665fc8a9824765f01c9Fredrik Roubert * {@inheritDoc} 9932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 994f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 9952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public DateIntervalInfo cloneAsThawed() { 9962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller DateIntervalInfo result = (DateIntervalInfo) (this.cloneUnfrozenDII()); 9972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return result; 9982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 9992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 10022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Parse skeleton, save each field's width. 10032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * It is used for looking for best match skeleton, 10042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * and adjust pattern field width. 10052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param skeleton skeleton to be parsed 10062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param skeletonFieldWidth parsed skeleton field width 10072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 10082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller static void parseSkeleton(String skeleton, int[] skeletonFieldWidth) { 10092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int PATTERN_CHAR_BASE = 0x41; 10102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for ( int i = 0; i < skeleton.length(); ++i ) { 10112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ++skeletonFieldWidth[skeleton.charAt(i) - PATTERN_CHAR_BASE]; 10122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* 10182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Check whether one field width is numeric while the other is string. 10192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 10202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * TODO (xji): make it general 10212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 10222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param fieldWidth one field width 10232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param anotherFieldWidth another field width 10242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param patternLetter pattern letter char 10252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return true if one field width is numeric and the other is string, 10262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * false otherwise. 10272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 10282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller private static boolean stringNumeric(int fieldWidth, 10292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int anotherFieldWidth, 10302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller char patternLetter) { 10312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( patternLetter == 'M' ) { 10322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( fieldWidth <= 2 && anotherFieldWidth > 2 || 10332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fieldWidth > 2 && anotherFieldWidth <= 2 ) { 10342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return true; 10352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10361c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert } 10372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return false; 10382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /* 10421c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * given an input skeleton, get the best match skeleton 10432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * which has pre-defined interval pattern in resource file. 10442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 10452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * TODO (xji): set field weight or 10462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * isolate the funtionality in DateTimePatternGenerator 10472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @param inputSkeleton input skeleton 10482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @return 0, if there is exact match for input skeleton 10491c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert * 1, if there is only field width difference between 10502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the best match and the input skeleton 10512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * 2, the only field difference is 'v' and 'z' 10522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * -1, if there is calendar field difference between 10532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the best match and the input skeleton 10542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 10552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller DateIntervalFormat.BestMatchInfo getBestSkeleton(String inputSkeleton) { 10562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller String bestSkeleton = inputSkeleton; 10572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int[] inputSkeletonFieldWidth = new int[58]; 10582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int[] skeletonFieldWidth = new int[58]; 10592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller final int DIFFERENT_FIELD = 0x1000; 10612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller final int STRING_NUMERIC_DIFFERENCE = 0x100; 10622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller final int BASE = 0x41; 10632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // TODO: this is a hack for 'v' and 'z' 10652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // resource bundle only have time skeletons ending with 'v', 10662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // but not for time skeletons ending with 'z'. 10672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller boolean replaceZWithV = false; 10682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( inputSkeleton.indexOf('z') != -1 ) { 10692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller inputSkeleton = inputSkeleton.replace('z', 'v'); 10702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller replaceZWithV = true; 10712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 10732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller parseSkeleton(inputSkeleton, inputSkeletonFieldWidth); 10742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int bestDistance = Integer.MAX_VALUE; 10752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // 0 means exact the same skeletons; 10762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // 1 means having the same field, but with different length, 10772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // 2 means only z/v differs 10782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // -1 means having different field. 10792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int bestFieldDifference = 0; 10802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (String skeleton : fIntervalPatterns.keySet()) { 10812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // clear skeleton field width 10822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for ( int i = 0; i < skeletonFieldWidth.length; ++i ) { 10831c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert skeletonFieldWidth[i] = 0; 10842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller parseSkeleton(skeleton, skeletonFieldWidth); 10862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller // calculate distance 10872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int distance = 0; 10882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int fieldDifference = 1; 10892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for ( int i = 0; i < inputSkeletonFieldWidth.length; ++i ) { 10902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int inputFieldWidth = inputSkeletonFieldWidth[i]; 10912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller int fieldWidth = skeletonFieldWidth[i]; 10922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( inputFieldWidth == fieldWidth ) { 10932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller continue; 10942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 10952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( inputFieldWidth == 0 ) { 10962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fieldDifference = -1; 10972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller distance += DIFFERENT_FIELD; 10982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else if ( fieldWidth == 0 ) { 10992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller fieldDifference = -1; 11002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller distance += DIFFERENT_FIELD; 11011c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert } else if (stringNumeric(inputFieldWidth, fieldWidth, 11022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller (char)(i+BASE) ) ) { 11032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller distance += STRING_NUMERIC_DIFFERENCE; 11042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } else { 11052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller distance += Math.abs(inputFieldWidth - fieldWidth); 11062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( distance < bestDistance ) { 11092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller bestSkeleton = skeleton; 11102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller bestDistance = distance; 11112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller bestFieldDifference = fieldDifference; 11122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( distance == 0 ) { 11142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller bestFieldDifference = 0; 11152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller break; 11162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( replaceZWithV && bestFieldDifference != -1 ) { 11192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller bestFieldDifference = 2; 11202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return new DateIntervalFormat.BestMatchInfo(bestSkeleton, bestFieldDifference); 11222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 11242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 11252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Override equals 11262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1127f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 11282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public boolean equals(Object a) { 11292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller if ( a instanceof DateIntervalInfo ) { 11302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller DateIntervalInfo dtInfo = (DateIntervalInfo)a; 11312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return fIntervalPatterns.equals(dtInfo.fIntervalPatterns); 11322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return false; 11342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller 11362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 11372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Override hashcode 11382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 1139f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert @Override 11402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public int hashCode() { 11412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return fIntervalPatterns.hashCode(); 11422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11431c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 11442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 11452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @deprecated This API is ICU internal only. 114693cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller * @hide original deprecated declaration 1147836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide draft / provisional / internal are hidden on Android 11482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 11492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Deprecated 11502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Map<String,Set<String>> getPatterns() { 11512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller LinkedHashMap<String,Set<String>> result = new LinkedHashMap<String,Set<String>>(); 11522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (Entry<String, Map<String, PatternInfo>> entry : fIntervalPatterns.entrySet()) { 11532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result.put(entry.getKey(), new LinkedHashSet<String>(entry.getValue().keySet())); 11542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return result; 11562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11571c8a530973739aafa823d758240d2cd5dad96fe3Fredrik Roubert 11582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller /** 11592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Get the internal patterns, with a deep clone for safety. 11602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @deprecated This API is ICU internal only. 116193cf604e9dd0525f15bc0a7450b2a35f3884c298Neil Fuller * @hide original deprecated declaration 1162836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide draft / provisional / internal are hidden on Android 11632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */ 11642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller @Deprecated 11652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller public Map<String, Map<String, PatternInfo>> getRawPatterns() { 11662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller LinkedHashMap<String, Map<String, PatternInfo>> result = new LinkedHashMap<String, Map<String, PatternInfo>>(); 11672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller for (Entry<String, Map<String, PatternInfo>> entry : fIntervalPatterns.entrySet()) { 11682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller result.put(entry.getKey(), new LinkedHashMap<String, PatternInfo>(entry.getValue())); 11692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller return result; 11712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller } 11722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller}// end class DateIntervalInfo 1173