17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/* 27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************** 3f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * Copyright (C) 2006-2015, Google, International Business Machines Corporation * 47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and others. All Rights Reserved. * 57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ******************************************************************************** 67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.text; 87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.ArrayList; 107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Arrays; 117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.BitSet; 127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Collection; 137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.EnumSet; 147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.HashSet; 157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Iterator; 167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.LinkedHashMap; 177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.LinkedHashSet; 187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.List; 197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Locale; 207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Map; 217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.MissingResourceException; 227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Set; 237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.TreeMap; 247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.TreeSet; 257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.ICUCache; 277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.ICUResourceBundle; 287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.PatternTokenizer; 297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.SimpleCache; 307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.Utility; 317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.Calendar; 327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.Freezable; 337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ICUCloneNotSupportedException; 347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ULocale; 357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ULocale.Category; 367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.UResourceBundle; 377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/** 397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This class provides flexible generation of date format patterns, like 407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "yy-MM-dd". The user can build up the generator by adding successive 417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * patterns. Once that is done, a query can be made using a "skeleton", which is 427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * a pattern which just includes the desired fields and lengths. The generator 437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * will return the "best fit" pattern corresponding to that skeleton. 447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The main method people will use is getBestPattern(String skeleton), since 467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * normally this class is pre-built with data from a particular locale. However, 477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * generators can be built directly from other data as well. 487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic class DateTimePatternGenerator implements Freezable<DateTimePatternGenerator>, Cloneable { 517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final boolean DEBUG = false; 527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // debugging flags 547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //static boolean SHOW_DISTANCE = false; 557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TODO add hack to fix months for CJK, as per bug ticket 1099 567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Create empty generator, to be constructed with addPattern(...) etc. 597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static DateTimePatternGenerator getEmptyInstance() { 627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new DateTimePatternGenerator(); 637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Only for use by subclasses 677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert protected DateTimePatternGenerator() { 707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Construct a flexible generator according to data for the default <code>FORMAT</code> locale. 747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see Category#FORMAT 757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static DateTimePatternGenerator getInstance() { 787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getInstance(ULocale.getDefault(Category.FORMAT)); 797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Construct a flexible generator according to data for a given locale. 837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param uLocale The locale to pass. 847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static DateTimePatternGenerator getInstance(ULocale uLocale) { 877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getFrozenInstance(uLocale).cloneAsThawed(); 887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Construct a flexible generator according to data for a given locale. 927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param locale The JDK locale to pass. 937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 54 947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static DateTimePatternGenerator getInstance(Locale locale) { 977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getInstance(ULocale.forLocale(locale)); 987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Construct a frozen instance of DateTimePatternGenerator for a 1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * given locale. This method returns a cached frozen instance of 1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * DateTimePatternGenerator, so less expensive than the regular 1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * factory method. 1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param uLocale The locale to pass. 1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return A frozen DateTimePatternGenerator. 1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static DateTimePatternGenerator getFrozenInstance(ULocale uLocale) { 1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String localeKey = uLocale.toString(); 1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateTimePatternGenerator result = DTPNG_CACHE.get(localeKey); 1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (result != null) { 1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result = new DateTimePatternGenerator(); 1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PatternInfo returnInfo = new PatternInfo(); 1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String shortTimePattern = null; 1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // first load with the ICU patterns 1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = DateFormat.FULL; i <= DateFormat.SHORT; ++i) { 1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateInstance(i, uLocale); 1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.addPattern(df.toPattern(), false, returnInfo); 1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert df = (SimpleDateFormat) DateFormat.getTimeInstance(i, uLocale); 1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.addPattern(df.toPattern(), false, returnInfo); 1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (i == DateFormat.SHORT) { 1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // keep this pattern to populate other time field 1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // combination patterns by hackTimes later in this method. 1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert shortTimePattern = df.toPattern(); 1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // use hour style in SHORT time pattern as the default 1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // hour style for the locale 1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FormatParser fp = new FormatParser(); 1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fp.set(shortTimePattern); 1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert List<Object> items = fp.getItems(); 1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int idx = 0; idx < items.size(); idx++) { 1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object item = items.get(idx); 1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (item instanceof VariableField) { 1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert VariableField fld = (VariableField)item; 1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (fld.getType() == HOUR) { 1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.defaultHourFormatChar = fld.toString().charAt(0); 1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle rb = (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, uLocale); 1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Get the correct calendar type 1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String calendarTypeToUse = uLocale.getKeywordValue("calendar"); 1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ( calendarTypeToUse == null ) { 1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] preferredCalendarTypes = Calendar.getKeywordValuesForLocale("calendar", uLocale, true); 1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert calendarTypeToUse = preferredCalendarTypes[0]; // the most preferred calendar 1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ( calendarTypeToUse == null ) { 1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert calendarTypeToUse = "gregorian"; // fallback 1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Get data for that calendar 1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // ICU4J getWithFallback does not work well when 1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 1) A nested table is an alias to /LOCALE/... 1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 2) getWithFallback is called multiple times for going down hierarchical resource path 1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // #9987 resolved the issue of alias table when full path is specified in getWithFallback, 1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // but there is no easy solution when the equivalent operation is done by multiple operations. 1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // This issue is addressed in #9964. 1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle itemBundle = rb.getWithFallback("calendar/" + calendarTypeToUse + "/appendItems"); 1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i=0; i<itemBundle.getSize(); ++i) { 1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle formatBundle = (ICUResourceBundle)itemBundle.get(i); 1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String formatName = itemBundle.get(i).getKey(); 1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String value = formatBundle.getString(); 1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.setAppendItemFormat(getAppendFormatNumber(formatName), value); 1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }catch(MissingResourceException e) { 1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // CLDR item names 1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle itemBundle = rb.getWithFallback("fields"); 1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle fieldBundle, dnBundle; 1827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i=0; i<TYPE_LIMIT; ++i) { 1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ( isCLDRFieldName(i) ) { 1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fieldBundle = itemBundle.getWithFallback(CLDR_FIELD_NAME[i]); 1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert dnBundle = fieldBundle.getWithFallback("dn"); 1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String value = dnBundle.getString(); 1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //System.out.println("Field name:"+value); 1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.setAppendItemName(i, value); 1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }catch(MissingResourceException e) { 1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // set the AvailableFormat in CLDR 1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle availFormatsBundle = null; 1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // ICU4J getWithFallback does not work well when 1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 1) A nested table is an alias to /LOCALE/... 1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 2) getWithFallback is called multiple times for going down hierarchical resource path 2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // #9987 resolved the issue of alias table when full path is specified in getWithFallback, 2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // but there is no easy solution when the equivalent operation is done by multiple operations. 2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // This issue is addressed in #9964. 2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert availFormatsBundle = rb.getWithFallback("calendar/" + calendarTypeToUse + "/availableFormats"); 2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (MissingResourceException e) { 2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // fall through 2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean override = true; 2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while (availFormatsBundle != null) { 2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < availFormatsBundle.getSize(); i++) { 2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String formatKey = availFormatsBundle.get(i).getKey(); 2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!result.isAvailableFormatSet(formatKey)) { 2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.setAvailableFormat(formatKey); 2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Add pattern with its associated skeleton. Override any duplicate derived from std patterns, 2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // but not a previous availableFormats entry: 2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String formatValue = availFormatsBundle.get(i).getString(); 2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.addPatternWithSkeleton(formatValue, formatKey, override, returnInfo); 2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle pbundle = (ICUResourceBundle)availFormatsBundle.getParent(); 2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (pbundle == null) { 2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert availFormatsBundle = pbundle.getWithFallback("calendar/" + calendarTypeToUse + "/availableFormats"); 2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (MissingResourceException e) { 2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert availFormatsBundle = null; 2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (availFormatsBundle != null && pbundle.getULocale().getBaseName().equals("root")) { 2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert override = false; 2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // assume it is always big endian (ok for CLDR right now) 2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // some languages didn't add mm:ss or HH:mm, so put in a hack to compute that from the short time. 2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (shortTimePattern != null) { 2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert hackTimes(result, returnInfo, shortTimePattern); 2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.setDateTimeFormat(Calendar.getDateTimePattern(Calendar.getInstance(uLocale), uLocale, DateFormat.MEDIUM)); 2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // decimal point for seconds 2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DecimalFormatSymbols dfs = new DecimalFormatSymbols(uLocale); 2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.setDecimal(String.valueOf(dfs.getDecimalSeparator())); 2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // freeze and cache 2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.freeze(); 2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DTPNG_CACHE.put(localeKey, result); 2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public char getDefaultHourFormatChar() { 2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return defaultHourFormatChar; 2617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void setDefaultHourFormatChar(char defaultHourFormatChar) { 2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.defaultHourFormatChar = defaultHourFormatChar; 2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static void hackTimes(DateTimePatternGenerator result, PatternInfo returnInfo, String hackPattern) { 2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.fp.set(hackPattern); 2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder mmss = new StringBuilder(); 2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // to get mm:ss, we strip all but mm literal ss 2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean gotMm = false; 2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < result.fp.items.size(); ++i) { 2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object item = result.fp.items.get(i); 2797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (item instanceof String) { 2807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (gotMm) { 2817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mmss.append(result.fp.quoteLiteral(item.toString())); 2827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 2847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert char ch = item.toString().charAt(0); 2857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (ch == 'm') { 2867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert gotMm = true; 2877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mmss.append(item); 2887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (ch == 's') { 2897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!gotMm) { 2907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; // failed 2917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mmss.append(item); 2937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.addPattern(mmss.toString(), false, returnInfo); 2947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 2957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (gotMm || ch == 'z' || ch == 'Z' || ch == 'v' || ch == 'V') { 2967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; // failed 2977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // to get hh:mm, we strip (literal ss) and (literal S) 3017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // the easiest way to do this is to mark the stuff we want to nuke, then remove it in a second pass. 3027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert BitSet variables = new BitSet(); 3037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert BitSet nuke = new BitSet(); 3047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < result.fp.items.size(); ++i) { 3057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object item = result.fp.items.get(i); 3067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (item instanceof VariableField) { 3077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert variables.set(i); 3087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert char ch = item.toString().charAt(0); 3097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (ch == 's' || ch == 'S') { 3107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert nuke.set(i); 3117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int j = i-1; j >= 0; ++j) { 3127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (variables.get(j)) break; 3137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert nuke.set(i); 3147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String hhmm = getFilteredPattern(result.fp, nuke); 3197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.addPattern(hhmm, false, returnInfo); 3207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String getFilteredPattern(FormatParser fp, BitSet nuke) { 3237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder result = new StringBuilder(); 3247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < fp.items.size(); ++i) { 3257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (nuke.get(i)) continue; 3267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object item = fp.items.get(i); 3277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (item instanceof String) { 3287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(fp.quoteLiteral(item.toString())); 3297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 3307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(item.toString()); 3317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result.toString(); 3347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /*private static int getAppendNameNumber(String string) { 3377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < CLDR_FIELD_NAME.length; ++i) { 3387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (CLDR_FIELD_NAME[i].equals(string)) return i; 3397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return -1; 3417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }*/ 3427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal CLDR 3457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 3467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 3487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static int getAppendFormatNumber(String string) { 3497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < CLDR_FIELD_APPEND.length; ++i) { 3507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (CLDR_FIELD_APPEND[i].equals(string)) return i; 3517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return -1; 3537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static boolean isCLDRFieldName(int index) { 3577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ((index<0) && (index>=TYPE_LIMIT)) { 3587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 3597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (CLDR_FIELD_NAME[index].charAt(0) == '*') { 3617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 3627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert else { 3647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 3657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return the best pattern matching the input skeleton. It is guaranteed to 3707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * have all of the fields in the skeleton. 3717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Example code:{@.jcite com.ibm.icu.samples.text.datetimepatterngenerator.DateTimePatternGeneratorSample:---getBestPatternExample} 3727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param skeleton The skeleton is a pattern containing only the variable fields. 3737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * For example, "MMMdd" and "mmhh" are skeletons. 3747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return Best pattern matching the input skeleton. 3757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 3767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getBestPattern(String skeleton) { 3787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getBestPattern(skeleton, null, MATCH_NO_OPTIONS); 3797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return the best pattern matching the input skeleton. It is guaranteed to 3837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * have all of the fields in the skeleton. 3847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 3857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param skeleton The skeleton is a pattern containing only the variable fields. 3867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * For example, "MMMdd" and "mmhh" are skeletons. 3877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param options MATCH_xxx options for forcing the length of specified fields in 3887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the returned pattern to match those in the skeleton (when this would 3897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * not happen otherwise). For default behavior, use MATCH_NO_OPTIONS. 3907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return Best pattern matching the input skeleton (and options). 3917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 3927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getBestPattern(String skeleton, int options) { 3947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getBestPattern(skeleton, null, options); 3957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 3987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * getBestPattern which takes optional skip matcher 3997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String getBestPattern(String skeleton, DateTimeMatcher skipMatcher, int options) { 4017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert EnumSet<DTPGflags> flags = EnumSet.noneOf(DTPGflags.class); 4027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Replace hour metacharacters 'j' and 'J', set flags as necessary 4037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder skeletonCopy = new StringBuilder(skeleton); 4047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean inQuoted = false; 4057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int patPos = 0; patPos < skeletonCopy.length(); patPos++) { 4067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert char patChr = skeletonCopy.charAt(patPos); 4077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (patChr == '\'') { 4087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert inQuoted = !inQuoted; 4097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (!inQuoted) { 4107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (patChr == 'j') { 4117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert skeletonCopy.setCharAt(patPos, defaultHourFormatChar); 4127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (patChr == 'J') { 4137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Get pattern for skeleton with H, then (in adjustFieldTypes) 4147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // replace H or k with defaultHourFormatChar 4157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert skeletonCopy.setCharAt(patPos, 'H'); 4167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert flags.add(DTPGflags.SKELETON_USES_CAP_J); 4177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String datePattern, timePattern; 4227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert synchronized(this) { 4237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert current.set(skeletonCopy.toString(), fp, false); 4247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PatternWithMatcher bestWithMatcher = getBestRaw(current, -1, _distanceInfo, skipMatcher); 4257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (_distanceInfo.missingFieldMask == 0 && _distanceInfo.extraFieldMask == 0) { 4267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // we have a good item. Adjust the field types 4277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return adjustFieldTypes(bestWithMatcher, current, flags, options); 4287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int neededFields = current.getFieldMask(); 4307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // otherwise break up by date and time. 4327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert datePattern = getBestAppending(current, neededFields & DATE_MASK, _distanceInfo, skipMatcher, flags, options); 4337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert timePattern = getBestAppending(current, neededFields & TIME_MASK, _distanceInfo, skipMatcher, flags, options); 4347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (datePattern == null) return timePattern == null ? "" : timePattern; 4377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (timePattern == null) return datePattern; 4387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return MessageFormat.format(getDateTimeFormat(), new Object[]{timePattern, datePattern}); 4397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * PatternInfo supplies output parameters for addPattern(...). It is used because 4437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Java doesn't have real output parameters. It is treated like a struct (eg 4447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Point), so all fields are public. 4457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 4467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 4477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final class PatternInfo { // struct for return information 4497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 4517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final int OK = 0; 4537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 4567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final int BASE_CONFLICT = 1; 4587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 4617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final int CONFLICT = 2; 4637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 4667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int status; 4687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 4717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String conflictingPattern; 4737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Simple constructor, since this is treated like a struct. 4767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 4777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public PatternInfo() { 4797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Adds a pattern to the generator. If the pattern has the same skeleton as 4847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * an existing pattern, and the override parameter is set, then the previous 4857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * value is overridden. Otherwise, the previous value is retained. In either 4867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * case, the conflicting information is returned in PatternInfo. 4877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 4887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Note that single-field patterns (like "MMM") are automatically added, and 4897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * don't need to be added explicitly! 4907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * * <p>Example code:{@.jcite com.ibm.icu.samples.text.datetimepatterngenerator.DateTimePatternGeneratorSample:---addPatternExample} 4917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param pattern Pattern to add. 4927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param override When existing values are to be overridden use true, otherwise 4937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * use false. 4947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param returnInfo Returned information. 4957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 4967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public DateTimePatternGenerator addPattern(String pattern, boolean override, PatternInfo returnInfo) { 4987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return addPatternWithSkeleton(pattern, null, override, returnInfo); 4997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * addPatternWithSkeleton: 5037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If skeletonToUse is specified, then an availableFormats entry is being added. In this case: 5047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 1. We pass that skeleton to DateTimeMatcher().set instead of having it derive a skeleton from the pattern. 5057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 2. If the new entry's skeleton or basePattern does match an existing entry but that entry also had a skeleton specified 5067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * (i.e. it was also from availableFormats), then the new entry does not override it regardless of the value of the override 5077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * parameter. This prevents later availableFormats entries from a parent locale overriding earlier ones from the actual 5087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * specified locale. However, availableFormats entries *should* override entries with matching skeleton whose skeleton was 5097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * derived (i.e. entries derived from the standard date/time patters for the specified locale). 5107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 3. When adding the pattern (skeleton2pattern.put, basePattern_pattern.put), we set a field to indicate that the added 5117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * entry had a specified skeleton. 5127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 5137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 5147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 5167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public DateTimePatternGenerator addPatternWithSkeleton(String pattern, String skeletonToUse, boolean override, PatternInfo returnInfo) { 5177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkFrozen(); 5187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateTimeMatcher matcher; 5197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (skeletonToUse == null) { 5207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert matcher = new DateTimeMatcher().set(pattern, fp, false); 5217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 5227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert matcher = new DateTimeMatcher().set(skeletonToUse, fp, false); 5237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String basePattern = matcher.getBasePattern(); 5257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // We only care about base conflicts - and replacing the pattern associated with a base - if: 5267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 1. the conflicting previous base pattern did *not* have an explicit skeleton; in that case the previous 5277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // base + pattern combination was derived from either (a) a canonical item, (b) a standard format, or 5287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // (c) a pattern specified programmatically with a previous call to addPattern (which would only happen 5297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if we are getting here from a subsequent call to addPattern). 5307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 2. a skeleton is specified for the current pattern, but override=false; in that case we are checking 5317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // availableFormats items from root, which should not override any previous entry with the same base. 5327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PatternWithSkeletonFlag previousPatternWithSameBase = basePattern_pattern.get(basePattern); 5337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (previousPatternWithSameBase != null && (!previousPatternWithSameBase.skeletonWasSpecified || (skeletonToUse != null && !override))) { 5347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert returnInfo.status = PatternInfo.BASE_CONFLICT; 5357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert returnInfo.conflictingPattern = previousPatternWithSameBase.pattern; 5367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!override) { 5377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 5387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // The only time we get here with override=true and skeletonToUse!=null is when adding availableFormats 5417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // items from CLDR data. In that case, we don't want an item from a parent locale to replace an item with 5427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // same skeleton from the specified locale, so skip the current item if skeletonWasSpecified is true for 5437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // the previously-specified conflicting item. 5447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PatternWithSkeletonFlag previousValue = skeleton2pattern.get(matcher); 5457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (previousValue != null) { 5467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert returnInfo.status = PatternInfo.CONFLICT; 5477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert returnInfo.conflictingPattern = previousValue.pattern; 5487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!override || (skeletonToUse != null && previousValue.skeletonWasSpecified)) return this; 5497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert returnInfo.status = PatternInfo.OK; 5517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert returnInfo.conflictingPattern = ""; 5527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PatternWithSkeletonFlag patWithSkelFlag = new PatternWithSkeletonFlag(pattern,skeletonToUse != null); 5537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (DEBUG) { 5547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert System.out.println(matcher + " => " + patWithSkelFlag); 5557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert skeleton2pattern.put(matcher, patWithSkelFlag); 5577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert basePattern_pattern.put(basePattern, patWithSkelFlag); 5587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 5597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Utility to return a unique skeleton from a given pattern. For example, 5637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * both "MMM-dd" and "dd/MMM" produce the skeleton "MMMdd". 5647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 5657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param pattern Input pattern, such as "dd/MMM" 5667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return skeleton, such as "MMMdd" 5677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 5687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getSkeleton(String pattern) { 5707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert synchronized (this) { // synchronized since a getter must be thread-safe 5717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert current.set(pattern, fp, false); 5727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return current.toString(); 5737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Same as getSkeleton, but allows duplicates 5787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 5797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param pattern Input pattern, such as "dd/MMM" 5807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return skeleton, such as "MMMdd" 5817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 5827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 5837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 5857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getSkeletonAllowingDuplicates(String pattern) { 5867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert synchronized (this) { // synchronized since a getter must be thread-safe 5877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert current.set(pattern, fp, true); 5887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return current.toString(); 5897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Same as getSkeleton, but allows duplicates 5947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and returns a string using canonical pattern chars 5957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 5967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param pattern Input pattern, such as "ccc, d LLL" 5977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return skeleton, such as "MMMEd" 5987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 5997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 6007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 6027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getCanonicalSkeletonAllowingDuplicates(String pattern) { 6037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert synchronized (this) { // synchronized since a getter must be thread-safe 6047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert current.set(pattern, fp, true); 6057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return current.toCanonicalString(); 6067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Utility to return a unique base skeleton from a given pattern. This is 6117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the same as the skeleton, except that differences in length are minimized 6127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * so as to only preserve the difference between string and numeric form. So 6137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * for example, both "MMM-dd" and "d/MMM" produce the skeleton "MMMd" 6147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * (notice the single d). 6157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 6167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param pattern Input pattern, such as "dd/MMM" 6177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return skeleton, such as "MMMdd" 6187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 6197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getBaseSkeleton(String pattern) { 6217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert synchronized (this) { // synchronized since a getter must be thread-safe 6227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert current.set(pattern, fp, false); 6237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return current.getBasePattern(); 6247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return a list of all the skeletons (in canonical form) from this class, 6297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and the patterns that they map to. 6307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 6317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param result an output Map in which to place the mapping from skeleton to 6327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * pattern. If you want to see the internal order being used, 6337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * supply a LinkedHashMap. If the input value is null, then a 6347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * LinkedHashMap is allocated. 6357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 6367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <i>Issue: an alternate API would be to just return a list of 6377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the skeletons, and then have a separate routine to get from 6387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * skeleton to pattern.</i> 6397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the input Map containing the values. 6407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 6417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Map<String, String> getSkeletons(Map<String, String> result) { 6437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (result == null) { 6447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result = new LinkedHashMap<String, String>(); 6457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (DateTimeMatcher item : skeleton2pattern.keySet()) { 6477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PatternWithSkeletonFlag patternWithSkelFlag = skeleton2pattern.get(item); 6487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String pattern = patternWithSkelFlag.pattern; 6497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (CANONICAL_SET.contains(pattern)) { 6507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 6517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.put(item.toString(), pattern); 6537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 6557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return a list of all the base skeletons (in canonical form) from this class 6597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 6607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Set<String> getBaseSkeletons(Set<String> result) { 6627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (result == null) { 6637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result = new HashSet<String>(); 6647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.addAll(basePattern_pattern.keySet()); 6667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 6677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Adjusts the field types (width and subtype) of a pattern to match what is 6717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * in a skeleton. That is, if you supply a pattern like "d-M H:m", and a 6727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * skeleton of "MMMMddhhmm", then the input pattern is adjusted to be 6737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "dd-MMMM hh:mm". This is used internally to get the best match for the 6747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * input skeleton, but can also be used externally. 6757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Example code:{@.jcite com.ibm.icu.samples.text.datetimepatterngenerator.DateTimePatternGeneratorSample:---replaceFieldTypesExample} 6767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param pattern input pattern 6777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param skeleton For the pattern to match to. 6787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return pattern adjusted to match the skeleton fields widths and subtypes. 6797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 6807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String replaceFieldTypes(String pattern, String skeleton) { 6827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return replaceFieldTypes(pattern, skeleton, MATCH_NO_OPTIONS); 6837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Adjusts the field types (width and subtype) of a pattern to match what is 6877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * in a skeleton. That is, if you supply a pattern like "d-M H:m", and a 6887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * skeleton of "MMMMddhhmm", then the input pattern is adjusted to be 6897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "dd-MMMM hh:mm". This is used internally to get the best match for the 6907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * input skeleton, but can also be used externally. 6917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 6927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param pattern input pattern 6937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param skeleton For the pattern to match to. 6947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param options MATCH_xxx options for forcing the length of specified fields in 6957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the returned pattern to match those in the skeleton (when this would 6967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * not happen otherwise). For default behavior, use MATCH_NO_OPTIONS. 6977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return pattern adjusted to match the skeleton fields widths and subtypes. 6987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 6997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String replaceFieldTypes(String pattern, String skeleton, int options) { 7017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert synchronized (this) { // synchronized since a getter must be thread-safe 7027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PatternWithMatcher patternNoMatcher = new PatternWithMatcher(pattern, null); 7037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return adjustFieldTypes(patternNoMatcher, current.set(skeleton, fp, false), EnumSet.noneOf(DTPGflags.class), options); 7047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The date time format is a message format pattern used to compose date and 7097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * time patterns. The default value is "{1} {0}", where {1} will be replaced 7107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * by the date pattern and {0} will be replaced by the time pattern. 7117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 7127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is used when the input skeleton contains both date and time fields, 7137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * but there is not a close match among the added patterns. For example, 7147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * suppose that this object was created by adding "dd-MMM" and "hh:mm", and 7157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * its datetimeFormat is the default "{1} {0}". Then if the input skeleton 7167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * is "MMMdhmm", there is not an exact match, so the input skeleton is 7177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * broken up into two components "MMMd" and "hmm". There are close matches 7187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * for those two skeletons, so the result is put together with this pattern, 7197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * resulting in "d-MMM h:mm". 7207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 7217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param dateTimeFormat message format pattern, where {1} will be replaced by the date 7227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * pattern and {0} will be replaced by the time pattern. 7237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 7247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void setDateTimeFormat(String dateTimeFormat) { 7267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkFrozen(); 7277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.dateTimeFormat = dateTimeFormat; 7287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Getter corresponding to setDateTimeFormat. 7327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 7337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return pattern 7347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 7357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDateTimeFormat() { 7377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return dateTimeFormat; 7387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The decimal value is used in formatting fractions of seconds. If the 7427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * skeleton contains fractional seconds, then this is used with the 7437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * fractional seconds. For example, suppose that the input pattern is 7447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "hhmmssSSSS", and the best matching pattern internally is "H:mm:ss", and 7457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the decimal string is ",". Then the resulting pattern is modified to be 7467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "H:mm:ss,SSSS" 7477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 7487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param decimal The decimal to set to. 7497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 7507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void setDecimal(String decimal) { 7527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkFrozen(); 7537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.decimal = decimal; 7547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Getter corresponding to setDecimal. 7587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return string corresponding to the decimal point 7597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 7607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDecimal() { 7627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return decimal; 7637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Redundant patterns are those which if removed, make no difference in the 7677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * resulting getBestPattern values. This method returns a list of them, to 7687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * help check the consistency of the patterns used to build this generator. 7697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 7707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param output stores the redundant patterns that are removed. To get these 7717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * in internal order, supply a LinkedHashSet. If null, a 7727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * collection is allocated. 7737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the collection with added elements. 7747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 7757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 7767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 7787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Collection<String> getRedundants(Collection<String> output) { 7797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert synchronized (this) { // synchronized since a getter must be thread-safe 7807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (output == null) { 7817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert output = new LinkedHashSet<String>(); 7827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (DateTimeMatcher cur : skeleton2pattern.keySet()) { 7847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PatternWithSkeletonFlag patternWithSkelFlag = skeleton2pattern.get(cur); 7857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String pattern = patternWithSkelFlag.pattern; 7867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (CANONICAL_SET.contains(pattern)) { 7877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 7887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String trial = getBestPattern(cur.toString(), cur, MATCH_NO_OPTIONS); 7907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (trial.equals(pattern)) { 7917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert output.add(pattern); 7927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ///CLOVER:OFF 7957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //The following would never be called since the parameter is false 7967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //Eclipse stated the following is "dead code" 7977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /*if (false) { // ordered 7987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateTimePatternGenerator results = new DateTimePatternGenerator(); 7997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PatternInfo pinfo = new PatternInfo(); 8007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (DateTimeMatcher cur : skeleton2pattern.keySet()) { 8017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String pattern = skeleton2pattern.get(cur); 8027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (CANONICAL_SET.contains(pattern)) { 8037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 8047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //skipMatcher = current; 8067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String trial = results.getBestPattern(cur.toString()); 8077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (trial.equals(pattern)) { 8087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert output.add(pattern); 8097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 8107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert results.addPattern(pattern, false, pinfo); 8117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }*/ 8147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ///CLOVER:ON 8157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return output; 8167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Field numbers, used for AppendItem functions 8207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 8237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final public int ERA = 0; 8257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 8287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final public int YEAR = 1; 8307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 8337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final public int QUARTER = 2; 8357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 8387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final public int MONTH = 3; 8407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 8437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final public int WEEK_OF_YEAR = 4; 8457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 8487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final public int WEEK_OF_MONTH = 5; 8507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 8537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final public int WEEKDAY = 6; 8557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 8587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final public int DAY = 7; 8607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 8637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final public int DAY_OF_YEAR = 8; 8657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 8687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final public int DAY_OF_WEEK_IN_MONTH = 9; 8707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 8737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final public int DAYPERIOD = 10; 8757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 8787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final public int HOUR = 11; 8807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 8837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final public int MINUTE = 12; 8857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 8887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final public int SECOND = 13; 8907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 8937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final public int FRACTIONAL_SECOND = 14; 8957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 8987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final public int ZONE = 15; 9007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 9037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final public int TYPE_LIMIT = 16; 9057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Option masks for getBestPattern, replaceFieldTypes (individual masks may be ORed together) 9077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Default option mask used for {@link #getBestPattern(String, int)} 9107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and {@link #replaceFieldTypes(String, String, int)}. 9117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 9127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getBestPattern(String, int) 9137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #replaceFieldTypes(String, String, int) 9147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final int MATCH_NO_OPTIONS = 0; 9167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Option mask for forcing the width of hour field. 9197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 9207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getBestPattern(String, int) 9217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #replaceFieldTypes(String, String, int) 9227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final int MATCH_HOUR_FIELD_LENGTH = 1 << HOUR; 9247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Option mask for forcing the width of minute field. 9277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 9287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 9297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 9317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final int MATCH_MINUTE_FIELD_LENGTH = 1 << MINUTE; 9327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Option mask for forcing the width of second field. 9357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 9367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 9377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 9397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final int MATCH_SECOND_FIELD_LENGTH = 1 << SECOND; 9407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Option mask for forcing the width of all date and time fields. 9437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 9447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getBestPattern(String, int) 9457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #replaceFieldTypes(String, String, int) 9467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final int MATCH_ALL_FIELDS_LENGTH = (1 << TYPE_LIMIT) - 1; 9487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * An AppendItem format is a pattern used to append a field if there is no 9517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * good match. For example, suppose that the input skeleton is "GyyyyMMMd", 9527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and there is no matching pattern internally, but there is a pattern 9537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * matching "yyyyMMMd", say "d-MM-yyyy". Then that pattern is used, plus the 9547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * G. The way these two are conjoined is by using the AppendItemFormat for G 9557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * (era). So if that value is, say "{0}, {1}" then the final resulting 9567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * pattern is "d-MM-yyyy, G". 9577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 9587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * There are actually three available variables: {0} is the pattern so far, 9597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {1} is the element we are adding, and {2} is the name of the element. 9607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 9617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This reflects the way that the CLDR data is organized. 9627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 9637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param field such as ERA 9647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param value pattern, such as "{0}, {1}" 9657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 9667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void setAppendItemFormat(int field, String value) { 9687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkFrozen(); 9697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendItemFormats[field] = value; 9707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Getter corresponding to setAppendItemFormats. Values below 0 or at or 9747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * above TYPE_LIMIT are illegal arguments. 9757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 9767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param field The index to retrieve the append item formats. 9777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return append pattern for field 9787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 9797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getAppendItemFormat(int field) { 9817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return appendItemFormats[field]; 9827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Sets the names of fields, eg "era" in English for ERA. These are only 9867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * used if the corresponding AppendItemFormat is used, and if it contains a 9877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {2} variable. 9887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 9897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This reflects the way that the CLDR data is organized. 9907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 9917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param field Index of the append item names. 9927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param value The value to set the item to. 9937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 9947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void setAppendItemName(int field, String value) { 9967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkFrozen(); 9977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendItemNames[field] = value; 9987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 10017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Getter corresponding to setAppendItemNames. Values below 0 or at or above 10027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * TYPE_LIMIT are illegal arguments. 10037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 10047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param field The index to get the append item name. 10057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return name for field 10067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 10077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getAppendItemName(int field) { 10097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return appendItemNames[field]; 10107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 10137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Determines whether a skeleton contains a single field 10147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 10157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param skeleton The skeleton to determine if it contains a single field. 10167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return true or not 10177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 10187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 10197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 10217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static boolean isSingleField(String skeleton) { 10227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert char first = skeleton.charAt(0); 10237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 1; i < skeleton.length(); ++i) { 10247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (skeleton.charAt(i) != first) return false; 10257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 10277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 10307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Add key to HashSet cldrAvailableFormatKeys. 10317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 10327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param key of the availableFormats in CLDR 10337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 10347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void setAvailableFormat(String key) { 10367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert checkFrozen(); 10377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cldrAvailableFormatKeys.add(key); 10387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 10417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This function checks the corresponding slot of CLDR_AVAIL_FORMAT_KEY[] 10427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * has been added to DateTimePatternGenerator. 10437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The function is to avoid the duplicate availableFomats added to 10447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the pattern map from parent locales. 10457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 10467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param key of the availableFormatMask in CLDR 10477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return TRUE if the corresponding slot of CLDR_AVAIL_FORMAT_KEY[] 10487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * has been added to DateTimePatternGenerator. 10497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 10507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private boolean isAvailableFormatSet(String key) { 10527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return cldrAvailableFormatKeys.contains(key); 10537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 10567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Boilerplate for Freezable 10577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 10587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isFrozen() { 10607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return frozen; 10617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 10647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Boilerplate for Freezable 10657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 10667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public DateTimePatternGenerator freeze() { 10687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert frozen = true; 10697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 10707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 10737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Boilerplate for Freezable 10747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 10757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public DateTimePatternGenerator cloneAsThawed() { 10777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateTimePatternGenerator result = (DateTimePatternGenerator) (this.clone()); 10787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert frozen = false; 10797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 10807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 10837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Boilerplate 10847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.6 10857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @SuppressWarnings("unchecked") 10877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Object clone() { 10887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 10897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateTimePatternGenerator result = (DateTimePatternGenerator) (super.clone()); 10907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.skeleton2pattern = (TreeMap<DateTimeMatcher, PatternWithSkeletonFlag>) skeleton2pattern.clone(); 10917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.basePattern_pattern = (TreeMap<String, PatternWithSkeletonFlag>) basePattern_pattern.clone(); 10927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.appendItemFormats = appendItemFormats.clone(); 10937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.appendItemNames = appendItemNames.clone(); 10947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.current = new DateTimeMatcher(); 10957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.fp = new FormatParser(); 10967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result._distanceInfo = new DistanceInfo(); 10977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.frozen = false; 10997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 11007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (CloneNotSupportedException e) { 11017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ///CLOVER:OFF 11027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new ICUCloneNotSupportedException("Internal Error", e); 11037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ///CLOVER:ON 11047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 11087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Utility class for FormatParser. Immutable class that is only used to mark 11097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the difference between a variable field and a literal string. Each 11107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * variable field must consist of 1 to n variable characters, representing 11117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * date format fields. For example, "VVVV" is valid while "V4" is not, nor 11127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * is "44". 11137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 11147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 11157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 11167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 11187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static class VariableField { 11197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final String string; 11207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final int canonicalIndex; 11217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 11237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Create a variable field: equivalent to VariableField(string,false); 11247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param string The string for the variable field. 11257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 11267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 11277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 11297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public VariableField(String string) { 11307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this(string, false); 11317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 11337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Create a variable field 11347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param string The string for the variable field 11357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param strict If true, then only allows exactly those lengths specified by CLDR for variables. For example, "hh:mm aa" would throw an exception. 11367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws IllegalArgumentException if the variable field is not valid. 11377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 11387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 11397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 11417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public VariableField(String string, boolean strict) { 11427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert canonicalIndex = DateTimePatternGenerator.getCanonicalIndex(string, strict); 11437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (canonicalIndex < 0) { 11447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Illegal datetime field:\t" 11457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + string); 11467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.string = string; 11487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 11517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Get the main type of this variable. These types are ERA, QUARTER, 11527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * MONTH, DAY, WEEK_OF_YEAR, WEEK_OF_MONTH, WEEKDAY, DAY, DAYPERIOD 11537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * (am/pm), HOUR, MINUTE, SECOND,FRACTIONAL_SECOND, ZONE. 11547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return main type. 11557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 11567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 11577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 11597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int getType() { 11607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return types[canonicalIndex][1]; 11617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 11647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 11657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 11667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 11687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getCanonicalCode(int type) { 11697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 11707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return CANONICAL_ITEMS[type]; 11717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (Exception e) { 11727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return String.valueOf(type); 11737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 11767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Check if the type of this variable field is numeric. 11777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return true if the type of this variable field is numeric. 11787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 11797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 11807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 11827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isNumeric() { 11837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return types[canonicalIndex][2] > 0; 11847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 11877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Private method. 11887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int getCanonicalIndex() { 11907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return canonicalIndex; 11917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 11947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Get the string represented by this variable. 11957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 11967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 11977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 11997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 12007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return string; 12017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 12057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This class provides mechanisms for parsing a SimpleDateFormat pattern 12067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or generating a new pattern, while handling the quoting. It represents 12077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the result of the parse as a list of items, where each item is either a 12087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * literal string or a variable field. When parsing It can be used to find 12097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * out which variable fields are in a date format, and in what order, such 12107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * as for presentation in a UI as separate text entry fields. It can also be 12117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * used to construct new SimpleDateFormats. 12127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Example: 12137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <pre> 12147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean containsZone(String pattern) { 12157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Iterator it = formatParser.set(pattern).getItems().iterator(); it.hasNext();) { 12167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object item = it.next(); 12177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (item instanceof VariableField) { 12187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert VariableField variableField = (VariableField) item; 12197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (variableField.getType() == DateTimePatternGenerator.ZONE) { 12207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 12217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 12257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </pre> 12277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 12287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 12297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 12307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 12317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static public class FormatParser { 12327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final UnicodeSet SYNTAX_CHARS = new UnicodeSet("[a-zA-Z]").freeze(); 12337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final UnicodeSet QUOTING_CHARS = new UnicodeSet("[[[:script=Latn:][:script=Cyrl:]]&[[:L:][:M:]]]").freeze(); 12347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient PatternTokenizer tokenizer = new PatternTokenizer() 12357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert .setSyntaxCharacters(SYNTAX_CHARS) 12367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert .setExtraQuotingCharacters(QUOTING_CHARS) 12377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert .setUsingQuote(true); 12387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private List<Object> items = new ArrayList<Object>(); 12397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 12417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Construct an empty date format parser, to which strings and variables can be added with set(...). 12427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 12437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 12447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 12457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 12467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public FormatParser() { 12477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 12507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Parses the string into a list of items. 12517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param string The string to parse. 12527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return this, for chaining 12537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 12547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 12557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 12567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 12577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert final public FormatParser set(String string) { 12587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return set(string, false); 12597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 12627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Parses the string into a list of items, taking into account all of the quoting that may be going on. 12637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param string The string to parse. 12647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param strict If true, then only allows exactly those lengths specified by CLDR for variables. For example, "hh:mm aa" would throw an exception. 12657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return this, for chaining 12667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 12677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 12687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 12697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 12707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public FormatParser set(String string, boolean strict) { 12717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert items.clear(); 12727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (string.length() == 0) return this; 12737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tokenizer.setPattern(string); 12747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuffer buffer = new StringBuffer(); 12757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuffer variable = new StringBuffer(); 12767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while (true) { 12777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buffer.setLength(0); 12787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int status = tokenizer.next(buffer); 12797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (status == PatternTokenizer.DONE) break; 12807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (status == PatternTokenizer.SYNTAX) { 12817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (variable.length() != 0 && buffer.charAt(0) != variable.charAt(0)) { 12827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert addVariable(variable, false); 12837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert variable.append(buffer); 12857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 12867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert addVariable(variable, false); 12877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert items.add(buffer.toString()); 12887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert addVariable(variable, false); 12917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 12927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void addVariable(StringBuffer variable, boolean strict) { 12957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (variable.length() != 0) { 12967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert items.add(new VariableField(variable.toString(), strict)); 12977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert variable.setLength(0); 12987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // /** Private method. Return a collection of fields. These will be a mixture of literal Strings and VariableFields. Any "a" variable field is removed. 13027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // * @param output List to append the items to. If null, is allocated as an ArrayList. 13037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // * @return list 13047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // */ 13057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // private List getVariableFields(List output) { 13067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (output == null) output = new ArrayList(); 13077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // main: 13087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // for (Iterator it = items.iterator(); it.hasNext();) { 13097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Object item = it.next(); 13107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (item instanceof VariableField) { 13117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // String s = item.toString(); 13127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // switch(s.charAt(0)) { 13137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // //case 'Q': continue main; // HACK 13147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // case 'a': continue main; // remove 13157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 13167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // output.add(item); 13177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 13187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 13197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // //System.out.println(output); 13207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // return output; 13217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 13227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // /** 13247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // * Produce a string which concatenates all the variables. That is, it is the logically the same as the input with all literals removed. 13257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // * @return a string which is a concatenation of all the variable fields 13267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // */ 13277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // public String getVariableFieldString() { 13287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // List list = getVariableFields(null); 13297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // StringBuffer result = new StringBuffer(); 13307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // for (Iterator it = list.iterator(); it.hasNext();) { 13317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // String item = it.next().toString(); 13327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // result.append(item); 13337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 13347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // return result.toString(); 13357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 13367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 13387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns modifiable list which is a mixture of Strings and VariableFields, in the order found during parsing. The strings represent literals, and have all quoting removed. Thus the string "dd 'de' MM" will parse into three items: 13397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <pre> 13407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * VariableField: dd 13417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * String: " de " 13427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * VariableField: MM 13437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </pre> 13447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The list is modifiable, so you can add any strings or variables to it, or remove any items. 13457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return modifiable list of items. 13467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 13477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 13487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 13497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 13507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public List<Object> getItems() { 13517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return items; 13527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** Provide display form of formatted input. Each literal string is quoted if necessary.. That is, if the input was "hh':'mm", the result would be "hh:mm", since the ":" doesn't need quoting. See quoteLiteral(). 13557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return printable output string 13567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 13577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 13587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 13597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 13607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 13617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return toString(0, items.size()); 13627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 13657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Provide display form of a segment of the parsed input. Each literal string is minimally quoted. That is, if the input was "hh':'mm", the result would be "hh:mm", since the ":" doesn't need quoting. See quoteLiteral(). 13667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param start item to start from 13677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param limit last item +1 13687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return printable output string 13697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 13707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 13717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 13727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 13737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString(int start, int limit) { 13747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder result = new StringBuilder(); 13757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = start; i < limit; ++i) { 13767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object item = items.get(i); 13777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (item instanceof String) { 13787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String itemString = (String) item; 13797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(tokenizer.quoteLiteral(itemString)); 13807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 13817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(items.get(i).toString()); 13827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result.toString(); 13857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 13887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns true if it has a mixture of date and time variable fields: that is, at least one date variable and at least one time variable. 13897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return true or false 13907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 13917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 13927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 13937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 13947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean hasDateAndTimeFields() { 13957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int foundMask = 0; 13967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Object item : items) { 13977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (item instanceof VariableField) { 13987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int type = ((VariableField)item).getType(); 13997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert foundMask |= 1 << type; 14007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean isDate = (foundMask & DATE_MASK) != 0; 14037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean isTime = (foundMask & TIME_MASK) != 0; 14047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return isDate && isTime; 14057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // /** 14087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // * Internal routine 14097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // * @param value 14107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // * @param result 14117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // * @return list 14127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // */ 14137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // public List getAutoPatterns(String value, List result) { 14147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (result == null) result = new ArrayList(); 14157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // int fieldCount = 0; 14167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // int minField = Integer.MAX_VALUE; 14177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // int maxField = Integer.MIN_VALUE; 14187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // for (Iterator it = items.iterator(); it.hasNext();) { 14197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Object item = it.next(); 14207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (item instanceof VariableField) { 14217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // try { 14227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // int type = ((VariableField)item).getType(); 14237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (minField > type) minField = type; 14247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (maxField < type) maxField = type; 14257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (type == ZONE || type == DAYPERIOD || type == WEEKDAY) return result; // skip anything with zones 14267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // fieldCount++; 14277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } catch (Exception e) { 14287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // return result; // if there are any funny fields, return 14297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 14307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 14317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 14327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (fieldCount < 3) return result; // skip 14337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // // trim from start 14347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // // trim first field IF there are no letters around it 14357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // // and it is either the min or the max field 14367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // // first field is either 0 or 1 14377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // for (int i = 0; i < items.size(); ++i) { 14387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Object item = items.get(i); 14397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (item instanceof VariableField) { 14407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // int type = ((VariableField)item).getType(); 14417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (type != minField && type != maxField) break; 14427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 14437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (i > 0) { 14447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Object previousItem = items.get(0); 14457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (alpha.containsSome(previousItem.toString())) break; 14467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 14477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // int start = i+1; 14487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (start < items.size()) { 14497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Object nextItem = items.get(start); 14507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (nextItem instanceof String) { 14517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (alpha.containsSome(nextItem.toString())) break; 14527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // start++; // otherwise skip over string 14537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 14547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 14557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // result.add(toString(start, items.size())); 14567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // break; 14577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 14587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 14597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // // now trim from end 14607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // for (int i = items.size()-1; i >= 0; --i) { 14617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Object item = items.get(i); 14627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (item instanceof VariableField) { 14637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // int type = ((VariableField)item).getType(); 14647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (type != minField && type != maxField) break; 14657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (i < items.size() - 1) { 14667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Object previousItem = items.get(items.size() - 1); 14677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (alpha.containsSome(previousItem.toString())) break; 14687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 14697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // int end = i-1; 14707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (end > 0) { 14717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Object nextItem = items.get(end); 14727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (nextItem instanceof String) { 14737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (alpha.containsSome(nextItem.toString())) break; 14747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // end--; // otherwise skip over string 14757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 14767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 14777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // result.add(toString(0, end+1)); 14787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // break; 14797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 14807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 14817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 14827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // return result; 14837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 14847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // private static UnicodeSet alpha = new UnicodeSet("[:alphabetic:]"); 14867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // private int getType(Object item) { 14887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // String s = item.toString(); 14897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // int canonicalIndex = getCanonicalIndex(s); 14907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (canonicalIndex < 0) { 14917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // throw new IllegalArgumentException("Illegal field:\t" 14927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // + s); 14937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 14947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // int type = types[canonicalIndex][1]; 14957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // return type; 14967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 14977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 14997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Each literal string is quoted as needed. That is, the ' quote marks will only be added if needed. The exact pattern of quoting is not guaranteed, thus " de la " could be quoted as " 'de la' " or as " 'de' 'la' ". 15007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param string The string to check. 15017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return string with quoted literals 15027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 15037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 15047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 15057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 15067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Object quoteLiteral(String string) { 15077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return tokenizer.quoteLiteral(string); 15087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 15137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Used by CLDR tooling; not in ICU4C. 15147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Note, this will not work correctly with normal skeletons, since fields 15157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * that should be related in the two skeletons being compared - like EEE and 15167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ccc, or y and U - will not be sorted in the same relative place as each 15177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * other when iterating over both TreeSets being compare, using TreeSet's 15187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "natural" code point ordering (this could be addressed by initializing 15197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the TreeSet with a comparator that compares fields first by their index 15207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * from getCanonicalIndex()). However if comparing canonical skeletons from 15217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * getCanonicalSkeletonAllowingDuplicates it will be OK regardless, since 15227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * in these skeletons all fields are normalized to the canonical pattern 15237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * char for those fields - M or L to M, E or c to E, y or U to y, etc. - 15247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * so corresponding fields will sort in the same way for both TreeMaps. 15257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 15267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 15277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 15287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 15297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean skeletonsAreSimilar(String id, String skeleton) { 15307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (id.equals(skeleton)) { 15317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; // fast path 15327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // must clone array, make sure items are in same order. 15347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TreeSet<String> parser1 = getSet(id); 15357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TreeSet<String> parser2 = getSet(skeleton); 15367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (parser1.size() != parser2.size()) { 15377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 15387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Iterator<String> it2 = parser2.iterator(); 15407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String item : parser1) { 15417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int index1 = getCanonicalIndex(item, false); 15427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String item2 = it2.next(); // same length so safe 15437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int index2 = getCanonicalIndex(item2, false); 15447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (types[index1][1] != types[index2][1]) { 15457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 15467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 15497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private TreeSet<String> getSet(String id) { 15527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert final List<Object> items = fp.set(id).getItems(); 15537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TreeSet<String> result = new TreeSet<String>(); 15547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Object obj : items) { 15557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert final String item = obj.toString(); 15567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (item.startsWith("G") || item.startsWith("a")) { 15577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 15587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.add(item); 15607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 15627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // ========= PRIVATES ============ 15657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static class PatternWithMatcher { 15677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String pattern; 15687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public DateTimeMatcher matcherWithSkeleton; 15697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Simple constructor 15707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public PatternWithMatcher(String pat, DateTimeMatcher matcher) { 15717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert pattern = pat; 15727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert matcherWithSkeleton = matcher; 15737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static class PatternWithSkeletonFlag { 15767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String pattern; 15777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean skeletonWasSpecified; 15787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Simple constructor 15797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public PatternWithSkeletonFlag(String pat, boolean skelSpecified) { 15807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert pattern = pat; 15817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert skeletonWasSpecified = skelSpecified; 15827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 15847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return pattern + "," + skeletonWasSpecified; 15857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private TreeMap<DateTimeMatcher, PatternWithSkeletonFlag> skeleton2pattern = new TreeMap<DateTimeMatcher, PatternWithSkeletonFlag>(); // items are in priority order 15887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private TreeMap<String, PatternWithSkeletonFlag> basePattern_pattern = new TreeMap<String, PatternWithSkeletonFlag>(); // items are in priority order 15897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String decimal = "?"; 15907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String dateTimeFormat = "{1} {0}"; 15917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String[] appendItemFormats = new String[TYPE_LIMIT]; 15927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String[] appendItemNames = new String[TYPE_LIMIT]; 15937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 15947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < TYPE_LIMIT; ++i) { 15957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendItemFormats[i] = "{0} \u251C{2}: {1}\u2524"; 15967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendItemNames[i] = "F" + i; 15977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private char defaultHourFormatChar = 'H'; 16007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //private boolean chineseMonthHack = false; 16017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //private boolean isComplete = false; 16027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private volatile boolean frozen = false; 16037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient DateTimeMatcher current = new DateTimeMatcher(); 16057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient FormatParser fp = new FormatParser(); 16067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient DistanceInfo _distanceInfo = new DistanceInfo(); 16077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int FRACTIONAL_MASK = 1<<FRACTIONAL_SECOND; 16097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int SECOND_AND_FRACTIONAL_MASK = (1<<SECOND) | (1<<FRACTIONAL_SECOND); 16107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Cache for DateTimePatternGenerator 16127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static ICUCache<String, DateTimePatternGenerator> DTPNG_CACHE = new SimpleCache<String, DateTimePatternGenerator>(); 16137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void checkFrozen() { 16157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (isFrozen()) { 16167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new UnsupportedOperationException("Attempt to modify frozen object"); 16177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 16217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * We only get called here if we failed to find an exact skeleton. We have broken it into date + time, and look for the pieces. 16227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If we fail to find a complete skeleton, we compose in a loop until we have all the fields. 16237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 16247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String getBestAppending(DateTimeMatcher source, int missingFields, DistanceInfo distInfo, DateTimeMatcher skipMatcher, EnumSet<DTPGflags> flags, int options) { 16257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String resultPattern = null; 16267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (missingFields != 0) { 16277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PatternWithMatcher resultPatternWithMatcher = getBestRaw(source, missingFields, distInfo, skipMatcher); 16287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert resultPattern = adjustFieldTypes(resultPatternWithMatcher, source, flags, options); 16297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while (distInfo.missingFieldMask != 0) { // precondition: EVERY single field must work! 16317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // special hack for SSS. If we are missing SSS, and we had ss but found it, replace the s field according to the 16337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // number separator 16347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ((distInfo.missingFieldMask & SECOND_AND_FRACTIONAL_MASK) == FRACTIONAL_MASK 16357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && (missingFields & SECOND_AND_FRACTIONAL_MASK) == SECOND_AND_FRACTIONAL_MASK) { 16367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert resultPatternWithMatcher.pattern = resultPattern; 16377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert flags = EnumSet.copyOf(flags); 16387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert flags.add(DTPGflags.FIX_FRACTIONAL_SECONDS); 16397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert resultPattern = adjustFieldTypes(resultPatternWithMatcher, source, flags, options); 16407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert distInfo.missingFieldMask &= ~FRACTIONAL_MASK; // remove bit 16417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 16427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int startingMask = distInfo.missingFieldMask; 16457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PatternWithMatcher tempWithMatcher = getBestRaw(source, distInfo.missingFieldMask, distInfo, skipMatcher); 16467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String temp = adjustFieldTypes(tempWithMatcher, source, flags, options); 16477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int foundMask = startingMask & ~distInfo.missingFieldMask; 16487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int topField = getTopBitNumber(foundMask); 16497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert resultPattern = MessageFormat.format(getAppendFormat(topField), new Object[]{resultPattern, temp, getAppendName(topField)}); 16507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return resultPattern; 16537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String getAppendName(int foundMask) { 16567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return "'" + appendItemNames[foundMask] + "'"; 16577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String getAppendFormat(int foundMask) { 16597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return appendItemFormats[foundMask]; 16607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // /** 16637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // * @param current2 16647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // * @return 16657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // */ 16667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // private String adjustSeconds(DateTimeMatcher current2) { 16677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // // TODO Auto-generated method stub 16687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // return null; 16697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 16707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 16727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param foundMask 16737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 16747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int getTopBitNumber(int foundMask) { 16757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int i = 0; 16767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while (foundMask != 0) { 16777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert foundMask >>>= 1; 16787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ++i; 16797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return i-1; 16817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 16847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 16857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 16867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void complete() { 16877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PatternInfo patternInfo = new PatternInfo(); 16887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // make sure that every valid field occurs once, with a "default" length 16897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < CANONICAL_ITEMS.length; ++i) { 16907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //char c = (char)types[i][0]; 16917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert addPattern(String.valueOf(CANONICAL_ITEMS[i]), false, patternInfo); 16927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //isComplete = true; 16947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 16967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert complete(); 16977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 17007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 17017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 17027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private PatternWithMatcher getBestRaw(DateTimeMatcher source, int includeMask, DistanceInfo missingFields, DateTimeMatcher skipMatcher) { 17037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (SHOW_DISTANCE) System.out.println("Searching for: " + source.pattern 17047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // + ", mask: " + showMask(includeMask)); 17057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int bestDistance = Integer.MAX_VALUE; 17067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PatternWithMatcher bestPatternWithMatcher = new PatternWithMatcher("", null); 17077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DistanceInfo tempInfo = new DistanceInfo(); 17087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (DateTimeMatcher trial : skeleton2pattern.keySet()) { 17097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (trial.equals(skipMatcher)) { 17107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 17117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int distance = source.getDistance(trial, includeMask, tempInfo); 17137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (SHOW_DISTANCE) System.out.println("\tDistance: " + trial.pattern + ":\t" 17147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // + distance + ",\tmissing fields: " + tempInfo); 17157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (distance < bestDistance) { 17167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert bestDistance = distance; 17177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PatternWithSkeletonFlag patternWithSkelFlag = skeleton2pattern.get(trial); 17187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert bestPatternWithMatcher.pattern = patternWithSkelFlag.pattern; 17197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // If the best raw match had a specified skeleton then return it too. 17207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // This can be passed through to adjustFieldTypes to help it do a better job. 17217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (patternWithSkelFlag.skeletonWasSpecified) { 17227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert bestPatternWithMatcher.matcherWithSkeleton = trial; 17237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 17247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert bestPatternWithMatcher.matcherWithSkeleton = null; 17257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert missingFields.setTo(tempInfo); 17277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (distance == 0) { 17287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 17297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return bestPatternWithMatcher; 17337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 17367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param fixFractionalSeconds TODO 17377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 17387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // flags values 17397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private enum DTPGflags { FIX_FRACTIONAL_SECONDS, SKELETON_USES_CAP_J }; 17407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String adjustFieldTypes(PatternWithMatcher patternWithMatcher, DateTimeMatcher inputRequest, EnumSet<DTPGflags> flags, int options) { 17427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fp.set(patternWithMatcher.pattern); 17437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder newPattern = new StringBuilder(); 17447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Object item : fp.getItems()) { 17457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (item instanceof String) { 17467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert newPattern.append(fp.quoteLiteral((String)item)); 17477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 17487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert final VariableField variableField = (VariableField) item; 17497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder fieldBuilder = new StringBuilder(variableField.toString()); 17507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // int canonicalIndex = getCanonicalIndex(field, true); 17517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (canonicalIndex < 0) { 17527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // continue; // don't adjust 17537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 17547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // int type = types[canonicalIndex][1]; 17557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int type = variableField.getType(); 17567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (flags.contains(DTPGflags.FIX_FRACTIONAL_SECONDS) && type == SECOND) { 17587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String newField = inputRequest.original[FRACTIONAL_SECOND]; 17597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fieldBuilder.append(decimal); 17607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fieldBuilder.append(newField); 17617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (inputRequest.type[type] != 0) { 17627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Here: 17637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // - "reqField" is the field from the originally requested skeleton, with length 17647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // "reqFieldLen". 17657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // - "field" is the field from the found pattern. 17667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 17677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // The adjusted field should consist of characters from the originally requested 17687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // skeleton, except in the case of HOUR or MONTH or WEEKDAY or YEAR, in which case it 17697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // should consist of characters from the found pattern. 17707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 17717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // The length of the adjusted field (adjFieldLen) should match that in the originally 17727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // requested skeleton, except that in the following cases the length of the adjusted field 17737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // should match that in the found pattern (i.e. the length of this pattern field should 17747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // not be adjusted): 17757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 1. type is HOUR and the corresponding bit in options is not set (ticket #7180). 17767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Note, we may want to implement a similar change for other numeric fields (MM, dd, 17777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // etc.) so the default behavior is to get locale preference for field length, but 17787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // options bits can be used to override this. 17797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 2. There is a specified skeleton for the found pattern and one of the following is true: 17807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // a) The length of the field in the skeleton (skelFieldLen) is equal to reqFieldLen. 17817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // b) The pattern field is numeric and the skeleton field is not, or vice versa. 17827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 17837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Old behavior was: 17847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // normally we just replace the field. However HOUR is special; we only change the length 17857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String reqField = inputRequest.original[type]; 17877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int reqFieldLen = reqField.length(); 17887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ( reqField.charAt(0) == 'E' && reqFieldLen < 3 ) { 17897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert reqFieldLen = 3; // 1-3 for E are equivalent to 3 for c,e 17907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int adjFieldLen = reqFieldLen; 17927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateTimeMatcher matcherWithSkeleton = patternWithMatcher.matcherWithSkeleton; 17937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ( (type == HOUR && (options & MATCH_HOUR_FIELD_LENGTH)==0) || 17947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert (type == MINUTE && (options & MATCH_MINUTE_FIELD_LENGTH)==0) || 17957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert (type == SECOND && (options & MATCH_SECOND_FIELD_LENGTH)==0) ) { 17967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert adjFieldLen = fieldBuilder.length(); 17977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (matcherWithSkeleton != null) { 17987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String skelField = matcherWithSkeleton.origStringForField(type); 17997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int skelFieldLen = skelField.length(); 18007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean patFieldIsNumeric = variableField.isNumeric(); 18017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean skelFieldIsNumeric = matcherWithSkeleton.fieldIsNumeric(type); 18027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (skelFieldLen == reqFieldLen || (patFieldIsNumeric && !skelFieldIsNumeric) || (skelFieldIsNumeric && !patFieldIsNumeric)) { 18037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // don't adjust the field length in the found pattern 18047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert adjFieldLen = fieldBuilder.length(); 18057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert char c = (type != HOUR && type != MONTH && type != WEEKDAY && (type != YEAR || reqField.charAt(0)=='Y'))? 18087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert reqField.charAt(0): fieldBuilder.charAt(0); 18097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (type == HOUR && flags.contains(DTPGflags.SKELETON_USES_CAP_J)) { 18107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert c = defaultHourFormatChar; 18117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fieldBuilder = new StringBuilder(); 18137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = adjFieldLen; i > 0; --i) fieldBuilder.append(c); 18147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert newPattern.append(fieldBuilder); 18167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //if (SHOW_DISTANCE) System.out.println("\tRaw: " + pattern); 18197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return newPattern.toString(); 18207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // public static String repeat(String s, int count) { 18237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // StringBuffer result = new StringBuffer(); 18247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // for (int i = 0; i < count; ++i) { 18257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // result.append(s); 18267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 18277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // return result.toString(); 18287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 18297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 18317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * internal routine 18327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param pattern The pattern that is passed. 18337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return field value 18347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 18357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 18367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 18377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 18387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getFields(String pattern) { 18397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fp.set(pattern); 18407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder newPattern = new StringBuilder(); 18417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Object item : fp.getItems()) { 18427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (item instanceof String) { 18437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert newPattern.append(fp.quoteLiteral((String)item)); 18447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 18457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert newPattern.append("{" + getName(item.toString()) + "}"); 18467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return newPattern.toString(); 18497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String showMask(int mask) { 18527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder result = new StringBuilder(); 18537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < TYPE_LIMIT; ++i) { 18547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ((mask & (1<<i)) == 0) 18557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 18567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (result.length() != 0) 18577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(" | "); 18587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(FIELD_NAME[i]); 18597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(" "); 18607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result.toString(); 18627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final String[] CLDR_FIELD_APPEND = { 18657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "Era", "Year", "Quarter", "Month", "Week", "*", "Day-Of-Week", 18667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "Day", "*", "*", "*", 18677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "Hour", "Minute", "Second", "*", "Timezone" 18687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }; 18697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final String[] CLDR_FIELD_NAME = { 18717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "era", "year", "*", "month", "week", "*", "weekday", 18727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "day", "*", "*", "dayperiod", 18737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "hour", "minute", "second", "*", "zone" 18747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }; 18757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final String[] FIELD_NAME = { 18777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "Era", "Year", "Quarter", "Month", "Week_in_Year", "Week_in_Month", "Weekday", 18787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "Day", "Day_Of_Year", "Day_of_Week_in_Month", "Dayperiod", 18797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "Hour", "Minute", "Second", "Fractional_Second", "Zone" 18807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }; 18817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final String[] CANONICAL_ITEMS = { 18847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "G", "y", "Q", "M", "w", "W", "E", 18857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "d", "D", "F", 18867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "H", "m", "s", "S", "v" 18877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }; 18887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final Set<String> CANONICAL_SET = new HashSet<String>(Arrays.asList(CANONICAL_ITEMS)); 18907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private Set<String> cldrAvailableFormatKeys = new HashSet<String>(20); 18917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int 18937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DATE_MASK = (1<<DAYPERIOD) - 1, 18947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TIME_MASK = (1<<TYPE_LIMIT) - 1 - DATE_MASK; 18957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int // numbers are chosen to express 'distance' 18977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DELTA = 0x10, 18987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert NUMERIC = 0x100, 18997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert NONE = 0, 19007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert NARROW = -0x101, 19017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert SHORT = -0x102, 19027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LONG = -0x103, 19037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert EXTRA_FIELD = 0x10000, 19047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert MISSING_FIELD = 0x1000; 19057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static private String getName(String s) { 19087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int i = getCanonicalIndex(s, true); 19097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String name = FIELD_NAME[types[i][1]]; 19107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int subtype = types[i][2]; 19117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean string = subtype < 0; 19127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (string) subtype = -subtype; 19137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (subtype < 0) name += ":S"; 19147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert else name += ":N"; 19157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return name; 19167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 19197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Get the canonical index, or return -1 if illegal. 19207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param s 19217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param strict TODO 19227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 19237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static int getCanonicalIndex(String s, boolean strict) { 19247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int len = s.length(); 19257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (len == 0) { 19267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return -1; 19277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int ch = s.charAt(0); 19297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // verify that all are the same character 19307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 1; i < len; ++i) { 19317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (s.charAt(i) != ch) { 19327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return -1; 19337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int bestRow = -1; 19367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < types.length; ++i) { 19377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] row = types[i]; 19387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (row[0] != ch) continue; 19397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert bestRow = i; 19407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (row[3] > len) continue; 19417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (row[row.length-1] < len) continue; 19427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return i; 19437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return strict ? -1 : bestRow; 19457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int[][] types = { 19487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // the order here makes a difference only when searching for single field. 19497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // format is: 19507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // pattern character, main type, weight, min length, weight 19517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'G', ERA, SHORT, 1, 3}, 19527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'G', ERA, LONG, 4}, 19537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'y', YEAR, NUMERIC, 1, 20}, 19557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'Y', YEAR, NUMERIC + DELTA, 1, 20}, 19567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'u', YEAR, NUMERIC + 2*DELTA, 1, 20}, 1957f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert {'r', YEAR, NUMERIC + 3*DELTA, 1, 20}, 19587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'U', YEAR, SHORT, 1, 3}, 19597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'U', YEAR, LONG, 4}, 19607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'U', YEAR, NARROW, 5}, 19617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'Q', QUARTER, NUMERIC, 1, 2}, 19637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'Q', QUARTER, SHORT, 3}, 19647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'Q', QUARTER, LONG, 4}, 19657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'q', QUARTER, NUMERIC + DELTA, 1, 2}, 19677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'q', QUARTER, SHORT + DELTA, 3}, 19687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'q', QUARTER, LONG + DELTA, 4}, 19697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'M', MONTH, NUMERIC, 1, 2}, 19717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'M', MONTH, SHORT, 3}, 19727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'M', MONTH, LONG, 4}, 19737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'M', MONTH, NARROW, 5}, 19747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'L', MONTH, NUMERIC + DELTA, 1, 2}, 19757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'L', MONTH, SHORT - DELTA, 3}, 19767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'L', MONTH, LONG - DELTA, 4}, 19777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'L', MONTH, NARROW - DELTA, 5}, 19787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'l', MONTH, NUMERIC + DELTA, 1, 1}, 19807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'w', WEEK_OF_YEAR, NUMERIC, 1, 2}, 19827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'W', WEEK_OF_MONTH, NUMERIC + DELTA, 1}, 19837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'E', WEEKDAY, SHORT, 1, 3}, 19857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'E', WEEKDAY, LONG, 4}, 19867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'E', WEEKDAY, NARROW, 5}, 19877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'c', WEEKDAY, NUMERIC + 2*DELTA, 1, 2}, 19887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'c', WEEKDAY, SHORT - 2*DELTA, 3}, 19897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'c', WEEKDAY, LONG - 2*DELTA, 4}, 19907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'c', WEEKDAY, NARROW - 2*DELTA, 5}, 19917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'e', WEEKDAY, NUMERIC + DELTA, 1, 2}, // 'e' is currently not used in CLDR data, should not be canonical 19927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'e', WEEKDAY, SHORT - DELTA, 3}, 19937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'e', WEEKDAY, LONG - DELTA, 4}, 19947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'e', WEEKDAY, NARROW - DELTA, 5}, 19957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'d', DAY, NUMERIC, 1, 2}, 19977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'D', DAY_OF_YEAR, NUMERIC + DELTA, 1, 3}, 19987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'F', DAY_OF_WEEK_IN_MONTH, NUMERIC + 2*DELTA, 1}, 19997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'g', DAY, NUMERIC + 3*DELTA, 1, 20}, // really internal use, so we don't care 20007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'a', DAYPERIOD, SHORT, 1}, 20027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'H', HOUR, NUMERIC + 10*DELTA, 1, 2}, // 24 hour 20047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'k', HOUR, NUMERIC + 11*DELTA, 1, 2}, 20057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'h', HOUR, NUMERIC, 1, 2}, // 12 hour 20067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'K', HOUR, NUMERIC + DELTA, 1, 2}, 20077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'m', MINUTE, NUMERIC, 1, 2}, 20097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'s', SECOND, NUMERIC, 1, 2}, 20117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'S', FRACTIONAL_SECOND, NUMERIC + DELTA, 1, 1000}, 20127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'A', SECOND, NUMERIC + 2*DELTA, 1, 1000}, 20137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'v', ZONE, SHORT - 2*DELTA, 1}, 20157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'v', ZONE, LONG - 2*DELTA, 4}, 20167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'z', ZONE, SHORT, 1, 3}, 20177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'z', ZONE, LONG, 4}, 20187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'Z', ZONE, NARROW - DELTA, 1, 3}, 20197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'Z', ZONE, LONG - DELTA, 4}, 20207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'Z', ZONE, SHORT - DELTA, 5}, 20217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'O', ZONE, SHORT - DELTA, 1}, 20227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'O', ZONE, LONG - DELTA, 4}, 20237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'V', ZONE, SHORT - DELTA, 1}, 20247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'V', ZONE, LONG - DELTA, 2}, 20257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'X', ZONE, NARROW - DELTA, 1}, 20267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'X', ZONE, SHORT - DELTA, 2}, 20277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'X', ZONE, LONG - DELTA, 4}, 20287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'x', ZONE, NARROW - DELTA, 1}, 20297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'x', ZONE, SHORT - DELTA, 2}, 20307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert {'x', ZONE, LONG - DELTA, 4}, 20317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }; 20327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static class DateTimeMatcher implements Comparable<DateTimeMatcher> { 20347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert //private String pattern = null; 20357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int[] type = new int[TYPE_LIMIT]; 20367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String[] original = new String[TYPE_LIMIT]; 20377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String[] baseOriginal = new String[TYPE_LIMIT]; 20387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // just for testing; fix to make multi-threaded later 20407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // private static FormatParser fp = new FormatParser(); 20417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String origStringForField(int field) { 20437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return original[field]; 20447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean fieldIsNumeric(int field) { 20477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return type[field] > 0; 20487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 20517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder result = new StringBuilder(); 20527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < TYPE_LIMIT; ++i) { 20537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (original[i].length() != 0) result.append(original[i]); 20547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result.toString(); 20567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // returns a string like toString but using the canonical character for most types, 20597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // e.g. M for M or L, E for E or c, y for y or U, etc. The hour field is canonicalized 20607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // to 'H' (for 24-hour types) or 'h' (for 12-hour types) 20617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toCanonicalString() { 20627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder result = new StringBuilder(); 20637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < TYPE_LIMIT; ++i) { 20647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (original[i].length() != 0) { 20657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // append a string of the same length using the canonical character 20667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int j = 0; j < types.length; ++j) { 20677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] row = types[j]; 20687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (row[1] == i) { 20697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert char originalChar = original[i].charAt(0); 20707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert char repeatChar = (originalChar=='h' || originalChar=='K')? 'h': (char)row[0]; 20717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(Utility.repeat(String.valueOf(repeatChar), original[i].length())); 20727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 20737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result.toString(); 20787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String getBasePattern() { 20817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder result = new StringBuilder(); 20827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < TYPE_LIMIT; ++i) { 20837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (baseOriginal[i].length() != 0) result.append(baseOriginal[i]); 20847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result.toString(); 20867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateTimeMatcher set(String pattern, FormatParser fp, boolean allowDuplicateFields) { 20897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < TYPE_LIMIT; ++i) { 20907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert type[i] = NONE; 20917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert original[i] = ""; 20927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert baseOriginal[i] = ""; 20937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fp.set(pattern); 20957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Object obj : fp.getItems()) { 20967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!(obj instanceof VariableField)) { 20977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 20987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert VariableField item = (VariableField)obj; 21007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String field = item.toString(); 21017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (field.charAt(0) == 'a') continue; // skip day period, special case 21027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int canonicalIndex = item.getCanonicalIndex(); 21037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if (canonicalIndex < 0) { 21047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // throw new IllegalArgumentException("Illegal field:\t" 21057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // + field + "\t in " + pattern); 21067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // } 21077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] row = types[canonicalIndex]; 21087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int typeValue = row[1]; 21097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (original[typeValue].length() != 0) { 2110f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert if ( allowDuplicateFields || 2111f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert (original[typeValue].charAt(0) == 'r' && field.charAt(0) == 'U') || 2112f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert (original[typeValue].charAt(0) == 'U' && field.charAt(0) == 'r') ) { 21137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 21147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Conflicting fields:\t" 21167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + original[typeValue] + ", " + field + "\t in " + pattern); 21177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert original[typeValue] = field; 21197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert char repeatChar = (char)row[0]; 21207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int repeatCount = row[3]; 21217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // #7930 removes hack to cap repeatCount at 3 21227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ("GEzvQ".indexOf(repeatChar) >= 0) repeatCount = 1; 21237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert baseOriginal[typeValue] = Utility.repeat(String.valueOf(repeatChar),repeatCount); 21247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int subTypeValue = row[2]; 21257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (subTypeValue > 0) subTypeValue += field.length(); 21267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert type[typeValue] = subTypeValue; 21277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 21297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 21317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 21327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 21337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 21347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int getFieldMask() { 21357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int result = 0; 21367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < type.length; ++i) { 21377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (type[i] != 0) result |= (1<<i); 21387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 21407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 21427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 21437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 21447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 21457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @SuppressWarnings("unused") 21467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert void extractFrom(DateTimeMatcher source, int fieldMask) { 21477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < type.length; ++i) { 21487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ((fieldMask & (1<<i)) != 0) { 21497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert type[i] = source.type[i]; 21507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert original[i] = source.original[i]; 21517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 21527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert type[i] = NONE; 21537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert original[i] = ""; 21547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 21587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int getDistance(DateTimeMatcher other, int includeMask, DistanceInfo distanceInfo) { 21597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int result = 0; 21607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert distanceInfo.clear(); 21617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < type.length; ++i) { 21627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int myType = (includeMask & (1<<i)) == 0 ? 0 : type[i]; 21637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int otherType = other.type[i]; 21647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (myType == otherType) continue; // identical (maybe both zero) add 0 21657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (myType == 0) { // and other is not 21667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result += EXTRA_FIELD; 21677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert distanceInfo.addExtra(i); 21687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (otherType == 0) { // and mine is not 21697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result += MISSING_FIELD; 21707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert distanceInfo.addMissing(i); 21717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 21727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result += Math.abs(myType - otherType); // square of mismatch 21737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 21767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 21787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int compareTo(DateTimeMatcher that) { 21797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < original.length; ++i) { 21807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int comp = original[i].compareTo(that.original[i]); 21817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (comp != 0) return -comp; 21827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 0; 21847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 21867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean equals(Object other) { 21877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!(other instanceof DateTimeMatcher)) { 21887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 21897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateTimeMatcher that = (DateTimeMatcher) other; 21917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < original.length; ++i) { 21927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!original[i].equals(that.original[i])) return false; 21937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 21957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int hashCode() { 21977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int result = 0; 21987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < original.length; ++i) { 21997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result ^= original[i].hashCode(); 22007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 22027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 22057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static class DistanceInfo { 22067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int missingFieldMask; 22077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int extraFieldMask; 22087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert void clear() { 22097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert missingFieldMask = extraFieldMask = 0; 22107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 22127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 22137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 22147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert void setTo(DistanceInfo other) { 22157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert missingFieldMask = other.missingFieldMask; 22167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert extraFieldMask = other.extraFieldMask; 22177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert void addMissing(int field) { 22197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert missingFieldMask |= (1<<field); 22207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert void addExtra(int field) { 22227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert extraFieldMask |= (1<<field); 22237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 22257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return "missingFieldMask: " + DateTimePatternGenerator.showMask(missingFieldMask) 22267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + ", extraFieldMask: " + DateTimePatternGenerator.showMask(extraFieldMask); 22277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert} 22307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert//eof 2231