17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/* 27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ********************************************************************** 3f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * Copyright (c) 2004-2015, International Business Machines 47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Corporation and others. All Rights Reserved. 57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ********************************************************************** 67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Author: Alan Liu 77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Created: April 20, 2004 87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Since: ICU 3.0 97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ********************************************************************** 107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.text; 127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.Externalizable; 147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.IOException; 157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.InvalidObjectException; 167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.ObjectInput; 177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.ObjectOutput; 187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.ObjectStreamException; 197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.text.FieldPosition; 207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.text.ParsePosition; 217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Arrays; 227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Collection; 237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Date; 247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.EnumMap; 257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.HashMap; 267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Locale; 277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Map; 287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.MissingResourceException; 297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.concurrent.ConcurrentHashMap; 307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.DontCareFieldPosition; 327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.ICUData; 337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.ICUResourceBundle; 347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.SimpleCache; 357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.SimplePatternFormatter; 367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.math.BigDecimal; 377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.PluralRules.Factory; 387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.PluralRules.StandardPluralCategories; 397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.Currency; 407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.CurrencyAmount; 417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.Measure; 427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.MeasureUnit; 437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.TimeZone; 447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ULocale; 457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.ULocale.Category; 467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.util.UResourceBundle; 477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert// If you update the examples in the doc, don't forget to update MesaureUnitTest.TestExamplesInDocs too. 497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/** 507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A formatter for Measure objects. 517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>To format a Measure object, first create a formatter 537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * object using a MeasureFormat factory method. Then use that 547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * object's format or formatMeasures methods. 557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Here is sample code: 577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <pre> 587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * MeasureFormat fmtFr = MeasureFormat.getInstance( 597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ULocale.FRENCH, FormatWidth.SHORT); 607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Measure measure = new Measure(23, MeasureUnit.CELSIUS); 617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // Output: 23 °C 637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * System.out.println(fmtFr.format(measure)); 647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Measure measureF = new Measure(70, MeasureUnit.FAHRENHEIT); 667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // Output: 70 °F 687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * System.out.println(fmtFr.format(measureF)); 697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * MeasureFormat fmtFrFull = MeasureFormat.getInstance( 717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ULocale.FRENCH, FormatWidth.WIDE); 727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // Output: 70 pieds et 5,3 pouces 737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * System.out.println(fmtFrFull.formatMeasures( 747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * new Measure(70, MeasureUnit.FOOT), 757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * new Measure(5.3, MeasureUnit.INCH))); 767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // Output: 1 pied et 1 pouce 787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * System.out.println(fmtFrFull.formatMeasures( 797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * new Measure(1, MeasureUnit.FOOT), 807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * new Measure(1, MeasureUnit.INCH))); 817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * MeasureFormat fmtFrNarrow = MeasureFormat.getInstance( 837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale.FRENCH, FormatWidth.NARROW); 847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // Output: 1′ 1″ 857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * System.out.println(fmtFrNarrow.formatMeasures( 867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * new Measure(1, MeasureUnit.FOOT), 877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * new Measure(1, MeasureUnit.INCH))); 887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * MeasureFormat fmtEn = MeasureFormat.getInstance(ULocale.ENGLISH, FormatWidth.WIDE); 917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * // Output: 1 inch, 2 feet 937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * fmtEn.formatMeasures( 947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * new Measure(1, MeasureUnit.INCH), 957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * new Measure(2, MeasureUnit.FOOT)); 967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </pre> 977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This class does not do conversions from one unit to another. It simply formats 997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * whatever units it is given 1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This class is immutable and thread-safe so long as its deprecated subclass, 1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * TimeUnitFormat, is never used. TimeUnitFormat is not thread-safe, and is 1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * mutable. Although this class has existing subclasses, this class does not support new 1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * sub-classes. 1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.text.UFormat 1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @author Alan Liu 1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic class MeasureFormat extends UFormat { 1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Generated by serialver from JDK 1.4.1_01 1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final long serialVersionUID = -7182021401701778240L; 1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final transient ImmutableNumberFormat numberFormat; 1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final transient FormatWidth formatWidth; 1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // PluralRules is documented as being immutable which implies thread-safety. 1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final transient PluralRules rules; 1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Measure unit -> format width -> plural form -> pattern ("{0} meters") 1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final transient Map<MeasureUnit, EnumMap<FormatWidth, QuantityFormatter>> unitToStyleToCountToFormat; 1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final transient NumericFormatters numericFormatters; 1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final transient ImmutableNumberFormat currencyFormat; 1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final transient ImmutableNumberFormat integerFormat; 1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final transient Map<MeasureUnit, EnumMap<FormatWidth, SimplePatternFormatter>> unitToStyleToPerUnitPattern; 1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final transient EnumMap<FormatWidth, SimplePatternFormatter> styleToPerPattern; 1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final SimpleCache<ULocale, MeasureFormatData> localeMeasureFormatData 1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert = new SimpleCache<ULocale, MeasureFormatData>(); 1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final SimpleCache<ULocale, NumericFormatters> localeToNumericDurationFormatters 1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert = new SimpleCache<ULocale,NumericFormatters>(); 1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final Map<MeasureUnit, Integer> hmsTo012 = 1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert new HashMap<MeasureUnit, Integer>(); 1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static { 1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert hmsTo012.put(MeasureUnit.HOUR, 0); 1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert hmsTo012.put(MeasureUnit.MINUTE, 1); 1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert hmsTo012.put(MeasureUnit.SECOND, 2); 1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // For serialization: sub-class types. 1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int MEASURE_FORMAT = 0; 1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int TIME_UNIT_FORMAT = 1; 1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final int CURRENCY_FORMAT = 2; 1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Formatting width enum. 1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 159f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 53 1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Be sure to update MeasureUnitTest.TestSerialFormatWidthEnum 1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // when adding an enum value. 1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public enum FormatWidth { 1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Spell out everything. 1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 168f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 53 1697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert WIDE("units", ListFormatter.Style.DURATION, NumberFormat.PLURALCURRENCYSTYLE), 1717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Abbreviate when possible. 1747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 175f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 53 1767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert SHORT("unitsShort", ListFormatter.Style.DURATION_SHORT, NumberFormat.ISOCURRENCYSTYLE), 1787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Brief. Use only a symbol for the unit when possible. 1817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 182f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 53 1837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert NARROW("unitsNarrow", ListFormatter.Style.DURATION_NARROW, NumberFormat.CURRENCYSTYLE), 1857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Identical to NARROW except when formatMeasures is called with 1887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * an hour and minute; minute and second; or hour, minute, and second Measures. 1897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * In these cases formatMeasures formats as 5:37:23 instead of 5h, 37m, 23s. 1907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 191f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 53 1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert NUMERIC("unitsNarrow", ListFormatter.Style.DURATION_NARROW, NumberFormat.CURRENCYSTYLE); 1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Be sure to update the toFormatWidth and fromFormatWidth() functions 1967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // when adding an enum value. 1977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert final String resourceKey; 1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final ListFormatter.Style listFormatterStyle; 2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final int currencyStyle; 2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private FormatWidth(String resourceKey, ListFormatter.Style style, int currencyStyle) { 2037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.resourceKey = resourceKey; 2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.listFormatterStyle = style; 2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.currencyStyle = currencyStyle; 2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ListFormatter.Style getListFormatterStyle() { 2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return listFormatterStyle; 2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int getCurrencyStyle() { 2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return currencyStyle; 2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Create a format from the locale, formatWidth, and format. 2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param locale the locale. 2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param formatWidth hints how long formatted strings should be. 2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The new MeasureFormat object. 223f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 53 2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static MeasureFormat getInstance(ULocale locale, FormatWidth formatWidth) { 2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getInstance(locale, formatWidth, NumberFormat.getInstance(locale)); 2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Create a format from the JDK locale, formatWidth, and format. 2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param locale the JDK locale. 2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param formatWidth hints how long formatted strings should be. 2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The new MeasureFormat object. 2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 54 2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static MeasureFormat getInstance(Locale locale, FormatWidth formatWidth) { 2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getInstance(ULocale.forLocale(locale), formatWidth); 2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Create a format from the locale, formatWidth, and format. 2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param locale the locale. 2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param formatWidth hints how long formatted strings should be. 2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param format This is defensively copied. 2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The new MeasureFormat object. 249f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 53 2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static MeasureFormat getInstance(ULocale locale, FormatWidth formatWidth, NumberFormat format) { 2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules rules = PluralRules.forLocale(locale); 2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert NumericFormatters formatters = null; 2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert MeasureFormatData data = localeMeasureFormatData.get(locale); 2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (data == null) { 2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert data = loadLocaleData(locale); 2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert localeMeasureFormatData.put(locale, data); 2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (formatWidth == FormatWidth.NUMERIC) { 2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert formatters = localeToNumericDurationFormatters.get(locale); 2617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (formatters == null) { 2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert formatters = loadNumericFormatters(locale); 2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert localeToNumericDurationFormatters.put(locale, formatters); 2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert NumberFormat intFormat = NumberFormat.getInstance(locale); 2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert intFormat.setMaximumFractionDigits(0); 2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert intFormat.setMinimumFractionDigits(0); 2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert intFormat.setRoundingMode(BigDecimal.ROUND_DOWN); 2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new MeasureFormat( 2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert locale, 2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert formatWidth, 2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert new ImmutableNumberFormat(format), 2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert rules, 2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert data.unitToStyleToCountToFormat, 2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert formatters, 2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert new ImmutableNumberFormat(NumberFormat.getInstance(locale, formatWidth.getCurrencyStyle())), 2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert new ImmutableNumberFormat(intFormat), 2797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert data.unitToStyleToPerUnitPattern, 2807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert data.styleToPerPattern); 2817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Create a format from the JDK locale, formatWidth, and format. 2857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 2867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param locale the JDK locale. 2877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param formatWidth hints how long formatted strings should be. 2887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param format This is defensively copied. 2897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The new MeasureFormat object. 2907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 54 2917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 2927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static MeasureFormat getInstance(Locale locale, FormatWidth formatWidth, NumberFormat format) { 2947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getInstance(ULocale.forLocale(locale), formatWidth, format); 2957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Able to format Collection<? extends Measure>, Measure[], and Measure 2997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * by delegating to formatMeasures. 3007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If the pos argument identifies a NumberFormat field, 3017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * then its indices are set to the beginning and end of the first such field 3027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * encountered. MeasureFormat itself does not supply any fields. 3037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 3047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Calling a 3057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>formatMeasures</code> method is preferred over calling 3067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * this method as they give better performance. 3077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 3087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param obj must be a Collection<? extends Measure>, Measure[], or Measure object. 3097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param toAppendTo Formatted string appended here. 3107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param pos Identifies a field in the formatted text. 3117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see java.text.Format#format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition) 3127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 313f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU53 3147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 3167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { 3177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int prevLength = toAppendTo.length(); 3187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FieldPosition fpos = 3197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert new FieldPosition(pos.getFieldAttribute(), pos.getField()); 3207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (obj instanceof Collection) { 3217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Collection<?> coll = (Collection<?>) obj; 3227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Measure[] measures = new Measure[coll.size()]; 3237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int idx = 0; 3247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Object o : coll) { 3257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!(o instanceof Measure)) { 3267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException(obj.toString()); 3277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert measures[idx++] = (Measure) o; 3297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert toAppendTo.append(formatMeasures(new StringBuilder(), fpos, measures)); 3317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (obj instanceof Measure[]) { 3327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert toAppendTo.append(formatMeasures(new StringBuilder(), fpos, (Measure[]) obj)); 3337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (obj instanceof Measure){ 3347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert toAppendTo.append(formatMeasure((Measure) obj, numberFormat, new StringBuilder(), fpos)); 3357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 3367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException(obj.toString()); 3377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) { 3397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert pos.setBeginIndex(fpos.getBeginIndex() + prevLength); 3407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert pos.setEndIndex(fpos.getEndIndex() + prevLength); 3417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return toAppendTo; 3437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Parses text from a string to produce a <code>Measure</code>. 3477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see java.text.Format#parseObject(java.lang.String, java.text.ParsePosition) 3487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws UnsupportedOperationException Not supported. 349f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @draft ICU 53 (Retain) 3507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 3517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 3537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Measure parseObject(String source, ParsePosition pos) { 3547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new UnsupportedOperationException(); 3557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Format a sequence of measures. Uses the ListFormatter unit lists. 3597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * So, for example, one could format “3 feet, 2 inches”. 3607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Zero values are formatted (eg, “3 feet, 0 inches”). It is the caller’s 3617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * responsibility to have the appropriate values in appropriate order, 3627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and using the appropriate Number values. Typically the units should be 3637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * in descending order, with all but the last Measure having integer values 3647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * (eg, not “3.2 feet, 2 inches”). 3657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 3667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param measures a sequence of one or more measures. 3677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the formatted string. 368f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 53 3697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final String formatMeasures(Measure... measures) { 3717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return formatMeasures( 3727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert new StringBuilder(), 3737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DontCareFieldPosition.INSTANCE, 3747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert measures).toString(); 3757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Format a range of measures, such as "3.4-5.1 meters". It is the caller’s 3797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * responsibility to have the appropriate values in appropriate order, 3807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and using the appropriate Number values. 3817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <br>Note: If the format doesn’t have enough decimals, or lowValue ≥ highValue, 3827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the result will be a degenerate range, like “5-5 meters”. 3837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <br>Currency Units are not yet supported. 3847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 3857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param lowValue low value in range 3867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param highValue high value in range 3877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the formatted string. 3887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 3897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 3907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 3927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final String formatMeasureRange(Measure lowValue, Measure highValue) { 3937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert MeasureUnit unit = lowValue.getUnit(); 3947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!unit.equals(highValue.getUnit())) { 3957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Units must match: " + unit + " ≠ " + highValue.getUnit()); 3967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Number lowNumber = lowValue.getNumber(); 3987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Number highNumber = highValue.getNumber(); 3997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert final boolean isCurrency = unit instanceof Currency; 4007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert UFieldPosition lowFpos = new UFieldPosition(); 4027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert UFieldPosition highFpos = new UFieldPosition(); 4037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuffer lowFormatted = null; 4047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuffer highFormatted = null; 4057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (isCurrency) { 4077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Currency currency = (Currency) unit; 4087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int fracDigits = currency.getDefaultFractionDigits(); 4097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int maxFrac = numberFormat.nf.getMaximumFractionDigits(); 4107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int minFrac = numberFormat.nf.getMinimumFractionDigits(); 4117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (fracDigits != maxFrac || fracDigits != minFrac) { 4127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DecimalFormat currentNumberFormat = (DecimalFormat) numberFormat.get(); 4137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert currentNumberFormat.setMaximumFractionDigits(fracDigits); 4147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert currentNumberFormat.setMinimumFractionDigits(fracDigits); 4157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert lowFormatted = currentNumberFormat.format(lowNumber, new StringBuffer(), lowFpos); 4167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert highFormatted = currentNumberFormat.format(highNumber, new StringBuffer(), highFpos); 4177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (lowFormatted == null) { 4207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert lowFormatted = numberFormat.format(lowNumber, new StringBuffer(), lowFpos); 4217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert highFormatted = numberFormat.format(highNumber, new StringBuffer(), highFpos); 4227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert final double lowDouble = lowNumber.doubleValue(); 4257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String keywordLow = rules.select(new PluralRules.FixedDecimal(lowDouble, 4267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert lowFpos.getCountVisibleFractionDigits(), lowFpos.getFractionDigits())); 4277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert final double highDouble = highNumber.doubleValue(); 4297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String keywordHigh = rules.select(new PluralRules.FixedDecimal(highDouble, 4307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert highFpos.getCountVisibleFractionDigits(), highFpos.getFractionDigits())); 4317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert final PluralRanges pluralRanges = Factory.getDefaultFactory().getPluralRanges(getLocale()); 4337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StandardPluralCategories resolvedCategory = pluralRanges.get( 4347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StandardPluralCategories.valueOf(keywordLow), StandardPluralCategories.valueOf(keywordHigh)); 4357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert SimplePatternFormatter rangeFormatter = getRangeFormat(getLocale(), formatWidth); 4377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String formattedNumber = rangeFormatter.format(lowFormatted, highFormatted); 4387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (isCurrency) { 4407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Nasty hack 4417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert currencyFormat.format(1d); // have to call this for the side effect 4427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Currency currencyUnit = (Currency) unit; 4447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder result = new StringBuilder(); 4457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendReplacingCurrency(currencyFormat.getPrefix(lowDouble >= 0), currencyUnit, resolvedCategory, result); 4467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(formattedNumber); 4477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendReplacingCurrency(currencyFormat.getSuffix(highDouble >= 0), currencyUnit, resolvedCategory, result); 4487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result.toString(); 4497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // StringBuffer buffer = new StringBuffer(); 4507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // CurrencyAmount currencyLow = (CurrencyAmount) lowValue; 4517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // CurrencyAmount currencyHigh = (CurrencyAmount) highValue; 4527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // FieldPosition pos = new FieldPosition(NumberFormat.INTEGER_FIELD); 4537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // currencyFormat.format(currencyLow, buffer, pos); 4547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // int startOfInteger = pos.getBeginIndex(); 4557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // StringBuffer buffer2 = new StringBuffer(); 4567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // FieldPosition pos2 = new FieldPosition(0); 4577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // currencyFormat.format(currencyHigh, buffer2, pos2); 4587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 4597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Map<FormatWidth, QuantityFormatter> styleToCountToFormat = unitToStyleToCountToFormat.get(lowValue.getUnit()); 4607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert QuantityFormatter countToFormat = styleToCountToFormat.get(formatWidth); 4617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert SimplePatternFormatter formatter = countToFormat.getByVariant(resolvedCategory.toString()); 4627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return formatter.format(formattedNumber); 4637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private void appendReplacingCurrency(String affix, Currency unit, StandardPluralCategories resolvedCategory, StringBuilder result) { 4677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String replacement = "¤"; 4687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int pos = affix.indexOf(replacement); 4697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (pos < 0) { 4707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert replacement = "XXX"; 4717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert pos = affix.indexOf(replacement); 4727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (pos < 0) { 4747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(affix); 4757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 4767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // for now, just assume single 4777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(affix.substring(0,pos)); 4787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // we have a mismatch between the number style and the currency style, so remap 4797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int currentStyle = formatWidth.getCurrencyStyle(); 4807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (currentStyle == NumberFormat.ISOCURRENCYSTYLE) { 4817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(unit.getCurrencyCode()); 4827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 4837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(unit.getName(currencyFormat.nf.getLocale(ULocale.ACTUAL_LOCALE), 4847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert currentStyle == NumberFormat.CURRENCYSTYLE ? Currency.SYMBOL_NAME : Currency.PLURAL_LONG_NAME, 4857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert resolvedCategory.toString(), null)); 4867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.append(affix.substring(pos+replacement.length())); 4887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 492f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * Formats a single measure per unit. 4937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 494f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * An example of such a formatted string is "3.5 meters per second." 495f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * 496f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @param measure the measure object. In above example, 3.5 meters. 497f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @param perUnit the per unit. In above example, it is MeasureUnit.SECOND 498f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @param appendTo formatted string appended here. 499f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @param pos The field position. 5007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return appendTo. 501f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @draft ICU 55 502f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @provisional This API might change or be removed in a future release. 5037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 504f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert public StringBuilder formatMeasurePerUnit( 505f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert Measure measure, 506f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert MeasureUnit perUnit, 507f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert StringBuilder appendTo, 508f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert FieldPosition pos) { 509f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert MeasureUnit resolvedUnit = MeasureUnit.resolveUnitPerUnit( 510f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert measure.getUnit(), perUnit); 511f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert if (resolvedUnit != null) { 512f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert Measure newMeasure = new Measure(measure.getNumber(), resolvedUnit); 513f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert return formatMeasure(newMeasure, numberFormat, appendTo, pos); 514f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert } 5157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FieldPosition fpos = new FieldPosition( 516f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert pos.getFieldAttribute(), pos.getField()); 517f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert int offset = withPerUnitAndAppend( 518f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert formatMeasure(measure, numberFormat, new StringBuilder(), fpos), 5197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert perUnit, 5207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendTo); 5217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) { 522f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert pos.setBeginIndex(fpos.getBeginIndex() + offset); 523f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert pos.setEndIndex(fpos.getEndIndex() + offset); 5247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return appendTo; 5267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Formats a sequence of measures. 5307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 5317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If the fieldPosition argument identifies a NumberFormat field, 5327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * then its indices are set to the beginning and end of the first such field 5337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * encountered. MeasureFormat itself does not supply any fields. 5347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 5357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param appendTo the formatted string appended here. 5367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param fieldPosition Identifies a field in the formatted text. 5377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param measures the measures to format. 5387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return appendTo. 5397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see MeasureFormat#formatMeasures(Measure...) 540f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 53 5417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public StringBuilder formatMeasures( 5437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder appendTo, FieldPosition fieldPosition, Measure... measures) { 5447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // fast track for trivial cases 5457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (measures.length == 0) { 5467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return appendTo; 5477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (measures.length == 1) { 5497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return formatMeasure(measures[0], numberFormat, appendTo, fieldPosition); 5507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (formatWidth == FormatWidth.NUMERIC) { 5537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // If we have just hour, minute, or second follow the numeric 5547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // track. 5557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Number[] hms = toHMS(measures); 5567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (hms != null) { 5577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return formatNumeric(hms, appendTo); 5587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ListFormatter listFormatter = ListFormatter.getInstance( 5627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert getLocale(), formatWidth.getListFormatterStyle()); 5637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (fieldPosition != DontCareFieldPosition.INSTANCE) { 5647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return formatMeasuresSlowTrack(listFormatter, appendTo, fieldPosition, measures); 5657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Fast track: No field position. 5677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] results = new String[measures.length]; 5687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < measures.length; i++) { 5697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert results[i] = formatMeasure( 5707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert measures[i], 5717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert i == measures.length - 1 ? numberFormat : integerFormat); 5727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return appendTo.append(listFormatter.format((Object[]) results)); 5747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Two MeasureFormats, a and b, are equal if and only if they have the same formatWidth, 5797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * locale, and equal number formats. 580f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 53 5817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 5837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final boolean equals(Object other) { 5847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (this == other) { 5857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 5867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!(other instanceof MeasureFormat)) { 5887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 5897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert MeasureFormat rhs = (MeasureFormat) other; 5917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // A very slow but safe implementation. 5927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getWidth() == rhs.getWidth() 5937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && getLocale().equals(rhs.getLocale()) 5947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && getNumberFormat().equals(rhs.getNumberFormat()); 5957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@inheritDoc} 599f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 53 6007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Override 6027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final int hashCode() { 6037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // A very slow but safe implementation. 6047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return (getLocale().hashCode() * 31 6057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + getNumberFormat().hashCode()) * 31 + getWidth().hashCode(); 6067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Get the format width this instance is using. 610f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 53 6117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public MeasureFormat.FormatWidth getWidth() { 6137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return formatWidth; 6147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Get the locale of this instance. 618f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 53 6197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public final ULocale getLocale() { 6217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getLocale(ULocale.VALID_LOCALE); 6227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Get a copy of the number format. 626f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 53 6277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public NumberFormat getNumberFormat() { 6297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return numberFormat.get(); 6307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return a formatter for CurrencyAmount objects in the given 6347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * locale. 6357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param locale desired locale 6367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return a formatter object 6377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 6387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static MeasureFormat getCurrencyFormat(ULocale locale) { 6407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new CurrencyFormat(locale); 6417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return a formatter for CurrencyAmount objects in the given 6457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * JDK locale. 6467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param locale desired JDK locale 6477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return a formatter object 6487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 54 6497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 6507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static MeasureFormat getCurrencyFormat(Locale locale) { 6527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getCurrencyFormat(ULocale.forLocale(locale)); 6537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return a formatter for CurrencyAmount objects in the default 6577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>FORMAT</code> locale. 6587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return a formatter object 6597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see Category#FORMAT 6607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 6617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static MeasureFormat getCurrencyFormat() { 6637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getCurrencyFormat(ULocale.getDefault(Category.FORMAT)); 6647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // This method changes the NumberFormat object as well to match the new locale. 6677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert MeasureFormat withLocale(ULocale locale) { 6687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return MeasureFormat.getInstance(locale, getWidth()); 6697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert MeasureFormat withNumberFormat(NumberFormat format) { 6727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new MeasureFormat( 6737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert getLocale(), 6747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.formatWidth, 6757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert new ImmutableNumberFormat(format), 6767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.rules, 6777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.unitToStyleToCountToFormat, 6787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.numericFormatters, 6797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.currencyFormat, 6807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.integerFormat, 6817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.unitToStyleToPerUnitPattern, 6827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.styleToPerPattern); 6837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private MeasureFormat( 6867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale locale, 6877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FormatWidth formatWidth, 6887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ImmutableNumberFormat format, 6897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert PluralRules rules, 6907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Map<MeasureUnit, EnumMap<FormatWidth, QuantityFormatter>> unitToStyleToCountToFormat, 6917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert NumericFormatters formatters, 6927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ImmutableNumberFormat currencyFormat, 6937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ImmutableNumberFormat integerFormat, 6947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Map<MeasureUnit, EnumMap<FormatWidth, SimplePatternFormatter>> unitToStyleToPerUnitPattern, 6957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert EnumMap<FormatWidth, SimplePatternFormatter> styleToPerPattern) { 6967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert setLocale(locale, locale); 6977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.formatWidth = formatWidth; 6987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.numberFormat = format; 6997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.rules = rules; 7007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.unitToStyleToCountToFormat = unitToStyleToCountToFormat; 7017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.numericFormatters = formatters; 7027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.currencyFormat = currencyFormat; 7037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.integerFormat = integerFormat; 7047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.unitToStyleToPerUnitPattern = unitToStyleToPerUnitPattern; 7057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.styleToPerPattern = styleToPerPattern; 7067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert MeasureFormat() { 7097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Make compiler happy by setting final fields to null. 7107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.formatWidth = null; 7117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.numberFormat = null; 7127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.rules = null; 7137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.unitToStyleToCountToFormat = null; 7147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.numericFormatters = null; 7157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.currencyFormat = null; 7167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.integerFormat = null; 7177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.unitToStyleToPerUnitPattern = null; 7187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.styleToPerPattern = null; 7197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static class NumericFormatters { 7227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private DateFormat hourMinute; 7237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private DateFormat minuteSecond; 7247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private DateFormat hourMinuteSecond; 7257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public NumericFormatters( 7277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateFormat hourMinute, 7287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateFormat minuteSecond, 7297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateFormat hourMinuteSecond) { 7307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.hourMinute = hourMinute; 7317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.minuteSecond = minuteSecond; 7327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.hourMinuteSecond = hourMinuteSecond; 7337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public DateFormat getHourMinute() { return hourMinute; } 7367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public DateFormat getMinuteSecond() { return minuteSecond; } 7377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public DateFormat getHourMinuteSecond() { return hourMinuteSecond; } 7387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static NumericFormatters loadNumericFormatters( 7417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale locale) { 7427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle r = (ICUResourceBundle)UResourceBundle. 743f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert getBundleInstance(ICUData.ICU_UNIT_BASE_NAME, locale); 7447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new NumericFormatters( 7457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert loadNumericDurationFormat(r, "hm"), 7467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert loadNumericDurationFormat(r, "ms"), 7477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert loadNumericDurationFormat(r, "hms")); 7487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns formatting data for all MeasureUnits except for currency ones. 7527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static MeasureFormatData loadLocaleData( 7547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale locale) { 7557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert QuantityFormatter.Builder builder = new QuantityFormatter.Builder(); 7567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Map<MeasureUnit, EnumMap<FormatWidth, QuantityFormatter>> unitToStyleToCountToFormat 7577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert = new HashMap<MeasureUnit, EnumMap<FormatWidth, QuantityFormatter>>(); 7587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Map<MeasureUnit, EnumMap<FormatWidth, SimplePatternFormatter>> unitToStyleToPerUnitPattern 7597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert = new HashMap<MeasureUnit, EnumMap<FormatWidth, SimplePatternFormatter>>(); 7607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle resource = (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUData.ICU_UNIT_BASE_NAME, locale); 7617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert EnumMap<FormatWidth, SimplePatternFormatter> styleToPerPattern = new EnumMap<FormatWidth, SimplePatternFormatter>(FormatWidth.class); 7627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (FormatWidth styleItem : FormatWidth.values()) { 7637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 7647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle unitTypeRes = resource.getWithFallback(styleItem.resourceKey); 7657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle compoundRes = unitTypeRes.getWithFallback("compound"); 7667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle perRes = compoundRes.getWithFallback("per"); 7677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert styleToPerPattern.put(styleItem, SimplePatternFormatter.compile(perRes.getString())); 7687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (MissingResourceException e) { 7697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // may not have compound/per for every width. 7707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 7717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fillInStyleMap(styleToPerPattern); 7747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (MeasureUnit unit : MeasureUnit.getAvailable()) { 7757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Currency data cannot be found here. Skip. 7767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (unit instanceof Currency) { 7777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 7787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert EnumMap<FormatWidth, QuantityFormatter> styleToCountToFormat = unitToStyleToCountToFormat.get(unit); 7807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (styleToCountToFormat == null) { 7817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert unitToStyleToCountToFormat.put(unit, styleToCountToFormat = new EnumMap<FormatWidth, QuantityFormatter>(FormatWidth.class)); 7827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert EnumMap<FormatWidth, SimplePatternFormatter> styleToPerUnitPattern = new EnumMap<FormatWidth, SimplePatternFormatter>(FormatWidth.class); 7847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert unitToStyleToPerUnitPattern.put(unit, styleToPerUnitPattern); 7857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (FormatWidth styleItem : FormatWidth.values()) { 7867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 7877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle unitTypeRes = resource.getWithFallback(styleItem.resourceKey); 7887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle unitsRes = unitTypeRes.getWithFallback(unit.getType()); 7897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle oneUnitRes = unitsRes.getWithFallback(unit.getSubtype()); 7907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert builder.reset(); 7917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean havePluralItem = false; 7927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int len = oneUnitRes.getSize(); 7937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < len; i++) { 7947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert UResourceBundle countBundle; 7957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 7967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert countBundle = oneUnitRes.get(i); 7977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (MissingResourceException e) { 7987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 7997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String resKey = countBundle.getKey(); 8017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (resKey.equals("dnam")) { 8027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; // skip display name & per pattern (new in CLDR 26 / ICU 54) for now, not part of plurals 8037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (resKey.equals("per")) { 8057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert styleToPerUnitPattern.put( 8067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert styleItem, SimplePatternFormatter.compile(countBundle.getString())); 8077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 8087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert havePluralItem = true; 8107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert builder.add(resKey, countBundle.getString()); 8117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (havePluralItem) { 8137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // might not have any plural items if countBundle only has "dnam" display name, for instance, 8147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // as with fr unitsNarrow/light/lux in CLDR 26 8157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert styleToCountToFormat.put(styleItem, builder.build()); 8167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (MissingResourceException e) { 8187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert continue; 8197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TODO: if no fallback available, get from root. 8227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fillInStyleMap(styleToCountToFormat); 8237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fillInStyleMap(styleToPerUnitPattern); 8247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new MeasureFormatData(unitToStyleToCountToFormat, unitToStyleToPerUnitPattern, styleToPerPattern); 8267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static <T> boolean fillInStyleMap(Map<FormatWidth, T> styleMap) { 8297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (styleMap.size() == FormatWidth.values().length) { 8307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 8317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert T fallback = styleMap.get(FormatWidth.SHORT); 8337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (fallback == null) { 8347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fallback = styleMap.get(FormatWidth.WIDE); 8357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (fallback == null) { 8377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 8387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (FormatWidth styleItem : FormatWidth.values()) { 8407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert T item = styleMap.get(styleItem); 8417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (item == null) { 8427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert styleMap.put(styleItem, fallback); 8437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 8467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 848f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert private int withPerUnitAndAppend( 849f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert CharSequence formatted, MeasureUnit perUnit, StringBuilder appendTo) { 8507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] offsets = new int[1]; 8517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Map<FormatWidth, SimplePatternFormatter> styleToPerUnitPattern = 8527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert unitToStyleToPerUnitPattern.get(perUnit); 8537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert SimplePatternFormatter perUnitPattern = styleToPerUnitPattern.get(formatWidth); 8547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (perUnitPattern != null) { 855f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert perUnitPattern.formatAndAppend(appendTo, offsets, formatted); 8567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return offsets[0]; 8577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert SimplePatternFormatter perPattern = styleToPerPattern.get(formatWidth); 8597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Map<FormatWidth, QuantityFormatter> styleToCountToFormat = unitToStyleToCountToFormat.get(perUnit); 8607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert QuantityFormatter countToFormat = styleToCountToFormat.get(formatWidth); 8617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String perUnitString = countToFormat.getByVariant("one").getPatternWithNoPlaceholders().trim(); 862f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert perPattern.formatAndAppend(appendTo, offsets, formatted, perUnitString); 8637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return offsets[0]; 8647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String formatMeasure(Measure measure, ImmutableNumberFormat nf) { 8677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return formatMeasure( 8687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert measure, nf, new StringBuilder(), 8697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DontCareFieldPosition.INSTANCE).toString(); 8707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private StringBuilder formatMeasure( 8737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Measure measure, 8747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ImmutableNumberFormat nf, 8757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder appendTo, 8767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FieldPosition fieldPosition) { 8777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (measure.getUnit() instanceof Currency) { 8787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return appendTo.append( 8797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert currencyFormat.format( 8807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert new CurrencyAmount(measure.getNumber(), (Currency) measure.getUnit()), 8817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert new StringBuffer(), 8827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fieldPosition)); 8837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Number n = measure.getNumber(); 8867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert MeasureUnit unit = measure.getUnit(); 8877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert UFieldPosition fpos = new UFieldPosition(fieldPosition.getFieldAttribute(), fieldPosition.getField()); 8887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuffer formattedNumber = nf.format(n, new StringBuffer(), fpos); 8897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String keyword = rules.select(new PluralRules.FixedDecimal(n.doubleValue(), fpos.getCountVisibleFractionDigits(), fpos.getFractionDigits())); 8907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Map<FormatWidth, QuantityFormatter> styleToCountToFormat = unitToStyleToCountToFormat.get(unit); 8927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert QuantityFormatter countToFormat = styleToCountToFormat.get(formatWidth); 8937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert SimplePatternFormatter formatter = countToFormat.getByVariant(keyword); 8947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int[] offsets = new int[1]; 895f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert formatter.formatAndAppend(appendTo, offsets, formattedNumber); 8967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (offsets[0] != -1) { // there is a number (may not happen with, say, Arabic dual) 8977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Fix field position 8987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) { 8997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fieldPosition.setBeginIndex(fpos.getBeginIndex() + offsets[0]); 9007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fieldPosition.setEndIndex(fpos.getEndIndex() + offsets[0]); 9017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return appendTo; 9047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final class MeasureFormatData { 9077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert MeasureFormatData( 9087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Map<MeasureUnit, EnumMap<FormatWidth, QuantityFormatter>> unitToStyleToCountToFormat, 9097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Map<MeasureUnit, EnumMap<FormatWidth, SimplePatternFormatter>> unitToStyleToPerUnitPattern, 9107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert EnumMap<FormatWidth, SimplePatternFormatter> styleToPerPattern) { 9117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.unitToStyleToCountToFormat = unitToStyleToCountToFormat; 9127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.unitToStyleToPerUnitPattern = unitToStyleToPerUnitPattern; 9137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.styleToPerPattern = styleToPerPattern; 9147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert final Map<MeasureUnit, EnumMap<FormatWidth, QuantityFormatter>> unitToStyleToCountToFormat; 9167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert final Map<MeasureUnit, EnumMap<FormatWidth, SimplePatternFormatter>> unitToStyleToPerUnitPattern; 9177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert final EnumMap<FormatWidth, SimplePatternFormatter> styleToPerPattern; 9187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Wrapper around NumberFormat that provides immutability and thread-safety. 9217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final class ImmutableNumberFormat { 9227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private NumberFormat nf; 9237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public ImmutableNumberFormat(NumberFormat nf) { 9257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.nf = (NumberFormat) nf.clone(); 9267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public synchronized NumberFormat get() { 9297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return (NumberFormat) nf.clone(); 9307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public synchronized StringBuffer format( 9337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Number n, StringBuffer buffer, FieldPosition pos) { 9347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return nf.format(n, buffer, pos); 9357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public synchronized StringBuffer format( 9387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert CurrencyAmount n, StringBuffer buffer, FieldPosition pos) { 9397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return nf.format(n, buffer, pos); 9407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @SuppressWarnings("unused") 9437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public synchronized String format(Number number) { 9447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return nf.format(number); 9457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getPrefix(boolean positive) { 9487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return positive ? ((DecimalFormat)nf).getPositivePrefix() : ((DecimalFormat)nf).getNegativePrefix(); 9497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getSuffix(boolean positive) { 9517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return positive ? ((DecimalFormat)nf).getPositiveSuffix() : ((DecimalFormat)nf).getPositiveSuffix(); 9527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final class PatternData { 9567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert final String prefix; 9577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert final String suffix; 9587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public PatternData(String pattern) { 9597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int pos = pattern.indexOf("{0}"); 9607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (pos < 0) { 9617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert prefix = pattern; 9627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert suffix = null; 9637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 9647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert prefix = pattern.substring(0,pos); 9657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert suffix = pattern.substring(pos+3); 9667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 9697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return prefix + "; " + suffix; 9707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object toTimeUnitProxy() { 9757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new MeasureProxy(getLocale(), formatWidth, numberFormat.get(), TIME_UNIT_FORMAT); 9767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object toCurrencyProxy() { 9797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new MeasureProxy(getLocale(), formatWidth, numberFormat.get(), CURRENCY_FORMAT); 9807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private StringBuilder formatMeasuresSlowTrack( 9837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ListFormatter listFormatter, 9847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder appendTo, 9857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FieldPosition fieldPosition, 9867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Measure... measures) { 9877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] results = new String[measures.length]; 9887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Zero out our field position so that we can tell when we find our field. 9907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FieldPosition fpos = new FieldPosition( 9917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fieldPosition.getFieldAttribute(), fieldPosition.getField()); 9927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int fieldPositionFoundIndex = -1; 9947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < measures.length; ++i) { 9957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ImmutableNumberFormat nf = (i == measures.length - 1 ? numberFormat : integerFormat); 9967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (fieldPositionFoundIndex == -1) { 9977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert results[i] = formatMeasure(measures[i], nf, new StringBuilder(), fpos).toString(); 9987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (fpos.getBeginIndex() != 0 || fpos.getEndIndex() != 0) { 9997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fieldPositionFoundIndex = i; 10007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 10027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert results[i] = formatMeasure(measures[i], nf); 10037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ListFormatter.FormattedListBuilder builder = 10067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert listFormatter.format(Arrays.asList(results), fieldPositionFoundIndex); 10077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Fix up FieldPosition indexes if our field is found. 10097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (builder.getOffset() != -1) { 10107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fieldPosition.setBeginIndex(fpos.getBeginIndex() + builder.getOffset() + appendTo.length()); 10117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fieldPosition.setEndIndex(fpos.getEndIndex() + builder.getOffset() + appendTo.length()); 10127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return appendTo.append(builder.toString()); 10147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // type is one of "hm", "ms" or "hms" 10177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static DateFormat loadNumericDurationFormat( 10187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle r, String type) { 10197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert r = r.getWithFallback(String.format("durationUnits/%s", type)); 10207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // We replace 'h' with 'H' because 'h' does not make sense in the context of durations. 10217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateFormat result = new SimpleDateFormat(r.getString().replace("h", "H")); 10227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.setTimeZone(TimeZone.GMT_ZONE); 10237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 10247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Returns hours in [0]; minutes in [1]; seconds in [2] out of measures array. If 10277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // unsuccessful, e.g measures has other measurements besides hours, minutes, seconds; 10287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // hours, minutes, seconds are out of order; or have negative values, returns null. 10297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // If hours, minutes, or seconds is missing from measures the corresponding element in 10307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // returned array will be null. 10317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Number[] toHMS(Measure[] measures) { 10327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Number[] result = new Number[3]; 10337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int lastIdx = -1; 10347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Measure m : measures) { 10357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (m.getNumber().doubleValue() < 0.0) { 10367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 10377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Integer idxObj = hmsTo012.get(m.getUnit()); 10397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (idxObj == null) { 10407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 10417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int idx = idxObj.intValue(); 10437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (idx <= lastIdx) { 10447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // hour before minute before second 10457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 10467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert lastIdx = idx; 10487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result[idx] = m.getNumber(); 10497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 10517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Formats numeric time duration as 5:00:47 or 3:54. In the process, it replaces any null 10547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // values in hms with 0. 10557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private StringBuilder formatNumeric(Number[] hms, StringBuilder appendable) { 10567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // find the start and end of non-nil values in hms array. We have to know if we 10587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // have hour-minute; minute-second; or hour-minute-second. 10597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int startIndex = -1; 10607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int endIndex = -1; 10617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < hms.length; i++) { 10627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (hms[i] != null) { 10637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert endIndex = i; 10647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (startIndex == -1) { 10657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert startIndex = endIndex; 10667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 10687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Replace nil value with 0. 10697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert hms[i] = Integer.valueOf(0); 10707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // convert hours, minutes, seconds into milliseconds. 10737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert long millis = (long) (((Math.floor(hms[0].doubleValue()) * 60.0 10747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + Math.floor(hms[1].doubleValue())) * 60.0 10757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + Math.floor(hms[2].doubleValue())) * 1000.0); 10767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Date d = new Date(millis); 10777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if hour-minute-second 10787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (startIndex == 0 && endIndex == 2) { 10797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return formatNumeric( 10807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert d, 10817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert numericFormatters.getHourMinuteSecond(), 10827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateFormat.Field.SECOND, 10837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert hms[endIndex], 10847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendable); 10857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if minute-second 10877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (startIndex == 1 && endIndex == 2) { 10887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return formatNumeric( 10897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert d, 10907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert numericFormatters.getMinuteSecond(), 10917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateFormat.Field.SECOND, 10927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert hms[endIndex], 10937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendable); 10947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if hour-minute 10967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (startIndex == 0 && endIndex == 1) { 10977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return formatNumeric( 10987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert d, 10997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert numericFormatters.getHourMinute(), 11007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateFormat.Field.MINUTE, 11017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert hms[endIndex], 11027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendable); 11037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalStateException(); 11057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Formats a duration as 5:00:37 or 23:59. 11087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // duration is a particular duration after epoch. 11097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // formatter is a hour-minute-second, hour-minute, or minute-second formatter. 11107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // smallestField denotes what the smallest field is in duration: either 11117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // hour, minute, or second. 11127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // smallestAmount is the value of that smallest field. for 5:00:37.3, 11137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // smallestAmount is 37.3. This smallest field is formatted with this object's 11147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // NumberFormat instead of formatter. 11157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // appendTo is where the formatted string is appended. 11167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private StringBuilder formatNumeric( 11177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Date duration, 11187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateFormat formatter, 11197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DateFormat.Field smallestField, 11207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Number smallestAmount, 11217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder appendTo) { 11227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Format the smallest amount ahead of time. 11237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String smallestAmountFormatted; 11247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Format the smallest amount using this object's number format, but keep track 11267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // of the integer portion of this formatted amount. We have to replace just the 11277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // integer part with the corresponding value from formatting the date. Otherwise 11287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // when formatting 0 minutes 9 seconds, we may get "00:9" instead of "00:09" 11297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FieldPosition intFieldPosition = new FieldPosition(NumberFormat.INTEGER_FIELD); 11307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert smallestAmountFormatted = numberFormat.format( 11317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert smallestAmount, new StringBuffer(), intFieldPosition).toString(); 11327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Give up if there is no integer field. 11337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (intFieldPosition.getBeginIndex() == 0 && intFieldPosition.getEndIndex() == 0) { 11347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalStateException(); 11357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Format our duration as a date, but keep track of where the smallest field is 11377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // so that we can use it to replace the integer portion of the smallest value. 11387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FieldPosition smallestFieldPosition = new FieldPosition(smallestField); 11397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String draft = formatter.format( 11407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert duration, new StringBuffer(), smallestFieldPosition).toString(); 11417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // If we find the smallest field 11437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (smallestFieldPosition.getBeginIndex() != 0 11447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert || smallestFieldPosition.getEndIndex() != 0) { 11457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // add everything up to the start of the smallest field in duration. 11467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendTo.append(draft, 0, smallestFieldPosition.getBeginIndex()); 11477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // add everything in the smallest field up to the integer portion 11497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendTo.append(smallestAmountFormatted, 0, intFieldPosition.getBeginIndex()); 11507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Add the smallest field in formatted duration in lieu of the integer portion 11527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // of smallest field 11537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendTo.append( 11547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert draft, 11557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert smallestFieldPosition.getBeginIndex(), 11567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert smallestFieldPosition.getEndIndex()); 11577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Add the rest of the smallest field 11597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendTo.append( 11607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert smallestAmountFormatted, 11617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert intFieldPosition.getEndIndex(), 11627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert smallestAmountFormatted.length()); 11637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendTo.append(draft, smallestFieldPosition.getEndIndex(), draft.length()); 11647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 11657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // As fallback, just use the formatted duration. 11667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendTo.append(draft); 11677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return appendTo; 11697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private Object writeReplace() throws ObjectStreamException { 11727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new MeasureProxy( 11737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert getLocale(), formatWidth, numberFormat.get(), MEASURE_FORMAT); 11747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static class MeasureProxy implements Externalizable { 11777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final long serialVersionUID = -6033308329886716770L; 11787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private ULocale locale; 11807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private FormatWidth formatWidth; 11817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private NumberFormat numberFormat; 11827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private int subClass; 11837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private HashMap<Object, Object> keyValues; 11847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public MeasureProxy( 11867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale locale, 11877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FormatWidth width, 11887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert NumberFormat numberFormat, 11897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int subClass) { 11907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.locale = locale; 11917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.formatWidth = width; 11927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.numberFormat = numberFormat; 11937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.subClass = subClass; 11947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.keyValues = new HashMap<Object, Object>(); 11957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Must have public constructor, to enable Externalizable 11987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public MeasureProxy() { 11997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void writeExternal(ObjectOutput out) throws IOException { 12027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert out.writeByte(0); // version 12037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert out.writeUTF(locale.toLanguageTag()); 12047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert out.writeByte(formatWidth.ordinal()); 12057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert out.writeObject(numberFormat); 12067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert out.writeByte(subClass); 12077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert out.writeObject(keyValues); 12087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @SuppressWarnings("unchecked") 12117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { 12127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert in.readByte(); // version. 12137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert locale = ULocale.forLanguageTag(in.readUTF()); 12147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert formatWidth = fromFormatWidthOrdinal(in.readByte() & 0xFF); 12157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert numberFormat = (NumberFormat) in.readObject(); 12167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (numberFormat == null) { 12177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new InvalidObjectException("Missing number format."); 12187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert subClass = in.readByte() & 0xFF; 12207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // This cast is safe because the serialized form of hashtable can have 12227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // any object as the key and any object as the value. 12237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert keyValues = (HashMap<Object, Object>) in.readObject(); 12247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (keyValues == null) { 12257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new InvalidObjectException("Missing optional values map."); 12267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private TimeUnitFormat createTimeUnitFormat() throws InvalidObjectException { 12307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int style; 12317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (formatWidth == FormatWidth.WIDE) { 12327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert style = TimeUnitFormat.FULL_NAME; 12337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (formatWidth == FormatWidth.SHORT) { 12347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert style = TimeUnitFormat.ABBREVIATED_NAME; 12357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 12367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new InvalidObjectException("Bad width: " + formatWidth); 12377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TimeUnitFormat result = new TimeUnitFormat(locale, style); 12397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result.setNumberFormat(numberFormat); 12407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 12417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private Object readResolve() throws ObjectStreamException { 12447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert switch (subClass) { 12457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case MEASURE_FORMAT: 12467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return MeasureFormat.getInstance(locale, formatWidth, numberFormat); 12477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case TIME_UNIT_FORMAT: 12487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return createTimeUnitFormat(); 12497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case CURRENCY_FORMAT: 12507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new CurrencyFormat(locale); 12517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert default: 12527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new InvalidObjectException("Unknown subclass: " + subClass); 12537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static FormatWidth fromFormatWidthOrdinal(int ordinal) { 12587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FormatWidth[] values = FormatWidth.values(); 12597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (ordinal < 0 || ordinal >= values.length) { 12607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return FormatWidth.WIDE; 12617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return values[ordinal]; 12637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static final Map<ULocale, SimplePatternFormatter> localeIdToRangeFormat 12667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert = new ConcurrentHashMap<ULocale, SimplePatternFormatter>(); 12677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 12697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return a simple pattern formatter for a range, such as "{0}–{1}". 12707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param forLocale locale to get the format for 12717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param width the format width 12727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return range formatter, such as "{0}–{1}" 12737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 12747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 12757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 12767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 12777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static SimplePatternFormatter getRangeFormat(ULocale forLocale, FormatWidth width) { 12797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TODO fix Hack for French 12807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (forLocale.getLanguage().equals("fr")) { 12817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getRangeFormat(ULocale.ROOT, width); 12827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert SimplePatternFormatter result = localeIdToRangeFormat.get(forLocale); 12847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (result == null) { 12857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ICUResourceBundle rb = (ICUResourceBundle)UResourceBundle. 12867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert getBundleInstance(ICUData.ICU_BASE_NAME, forLocale); 12877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale realLocale = rb.getULocale(); 12887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!forLocale.equals(realLocale)) { // if the child would inherit, then add a cache entry for it. 12897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result = localeIdToRangeFormat.get(forLocale); 12907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (result != null) { 12917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert localeIdToRangeFormat.put(forLocale, result); 12927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 12937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // At this point, both the forLocale and the realLocale don't have an item 12967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // So we have to make one. 12977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert NumberingSystem ns = NumberingSystem.getInstance(forLocale); 12987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String resultString = null; 13007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 13017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert resultString = rb.getStringWithFallback("NumberElements/" + ns.getName() + "/miscPatterns/range"); 13027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch ( MissingResourceException ex ) { 13037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert resultString = rb.getStringWithFallback("NumberElements/latn/patterns/range"); 13047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert result = SimplePatternFormatter.compile(resultString); 13067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert localeIdToRangeFormat.put(forLocale, result); 13077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!forLocale.equals(realLocale)) { 13087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert localeIdToRangeFormat.put(realLocale, result); 13097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return result; 13127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 13157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Return a simple pattern pattern for a range, such as "{0}–{1}" or "{0}~{1}". 13167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param forLocale locale to get the range pattern for 13177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param width the format width. 13187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return range pattern 13197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 13207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 13217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 13227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 13237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getRangePattern(ULocale forLocale, FormatWidth width) { 13247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getRangeFormat(forLocale, width).toString(); 13257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert} 1327