1 /* GENERATED SOURCE. DO NOT MODIFY. */
2 // © 2017 and later: Unicode, Inc. and others.
3 // License & terms of use: http://www.unicode.org/copyright.html#License
4 package ohos.global.icu.text;
5
6 import java.io.IOException;
7 import java.io.ObjectInputStream;
8 import java.io.ObjectOutputStream;
9 import java.io.ObjectStreamField;
10 import java.math.BigInteger;
11 import java.math.RoundingMode;
12 import java.text.AttributedCharacterIterator;
13 import java.text.FieldPosition;
14 import java.text.ParsePosition;
15
16 import ohos.global.icu.impl.FormattedStringBuilder;
17 import ohos.global.icu.impl.FormattedValueStringBuilderImpl;
18 import ohos.global.icu.impl.Utility;
19 import ohos.global.icu.impl.number.AffixUtils;
20 import ohos.global.icu.impl.number.DecimalFormatProperties;
21 import ohos.global.icu.impl.number.DecimalFormatProperties.ParseMode;
22 import ohos.global.icu.impl.number.DecimalQuantity;
23 import ohos.global.icu.impl.number.DecimalQuantity_DualStorageBCD;
24 import ohos.global.icu.impl.number.Padder;
25 import ohos.global.icu.impl.number.Padder.PadPosition;
26 import ohos.global.icu.impl.number.PatternStringParser;
27 import ohos.global.icu.impl.number.PatternStringUtils;
28 import ohos.global.icu.impl.number.parse.NumberParserImpl;
29 import ohos.global.icu.impl.number.parse.ParsedNumber;
30 import ohos.global.icu.lang.UCharacter;
31 import ohos.global.icu.math.BigDecimal;
32 import ohos.global.icu.math.MathContext;
33 import ohos.global.icu.number.FormattedNumber;
34 import ohos.global.icu.number.LocalizedNumberFormatter;
35 import ohos.global.icu.number.NumberFormatter;
36 import ohos.global.icu.text.PluralRules.IFixedDecimal;
37 import ohos.global.icu.util.Currency;
38 import ohos.global.icu.util.Currency.CurrencyUsage;
39 import ohos.global.icu.util.CurrencyAmount;
40 import ohos.global.icu.util.ULocale;
41 import ohos.global.icu.util.ULocale.Category;
42
43 /**
44 * <strong>[icu enhancement]</strong> ICU's replacement for {@link java.text.DecimalFormat}. Methods, fields, and other functionality specific to ICU are labeled '<strong>[icu]</strong>'.
45 *
46 * <p>
47 * <strong>IMPORTANT:</strong> New users are strongly encouraged to see if
48 * {@link NumberFormatter} fits their use case. Although not deprecated, this
49 * class, DecimalFormat, is only provided for java.text.DecimalFormat compatibility.
50 * <hr>
51 *
52 * <code>DecimalFormat</code> is the primary
53 * concrete subclass of {@link NumberFormat}. It has a variety of features designed to make it
54 * possible to parse and format numbers in any locale, including support for Western, Arabic, or
55 * Indic digits. It supports different flavors of numbers, including integers ("123"), fixed-point
56 * numbers ("123.4"), scientific notation ("1.23E4"), percentages ("12%"), and currency amounts
57 * ("$123.00", "USD123.00", "123.00 US dollars"). All of these flavors can be easily localized.
58 *
59 * <p>To obtain a number formatter for a specific locale (including the default locale), call one of
60 * NumberFormat's factory methods such as {@link NumberFormat#getInstance}. Do not call
61 * DecimalFormat constructors directly unless you know what you are doing.
62 *
63 * <p>DecimalFormat aims to comply with the specification <a
64 * href="http://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns">UTS #35</a>. Read
65 * the specification for more information on how all the properties in DecimalFormat fit together.
66 *
67 * <p><strong>NOTE:</strong> Starting in ICU 60, there is a new set of APIs for localized number
68 * formatting that are designed to be an improvement over DecimalFormat. New users are discouraged
69 * from using DecimalFormat. For more information, see the package ohos.global.icu.number.
70 *
71 * <h3>Example Usage</h3>
72 *
73 * <p>Customize settings on a DecimalFormat instance from the NumberFormat factory:
74 *
75 * <blockquote>
76 *
77 * <pre>
78 * NumberFormat f = NumberFormat.getInstance(loc);
79 * if (f instanceof DecimalFormat) {
80 * ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true);
81 * ((DecimalFormat) f).setMinimumGroupingDigits(2);
82 * }
83 * </pre>
84 *
85 * </blockquote>
86 *
87 * <p>Quick and dirty print out a number using the localized number, currency, and percent format
88 * for each locale:
89 *
90 * <blockquote>
91 *
92 * <pre>
93 * for (ULocale uloc : ULocale.getAvailableLocales()) {
94 * System.out.print(uloc + ":\t");
95 * System.out.print(NumberFormat.getInstance(uloc).format(1.23));
96 * System.out.print("\t");
97 * System.out.print(NumberFormat.getCurrencyInstance(uloc).format(1.23));
98 * System.out.print("\t");
99 * System.out.print(NumberFormat.getPercentInstance(uloc).format(1.23));
100 * System.out.println();
101 * }
102 * </pre>
103 *
104 * </blockquote>
105 *
106 * <h3>Properties and Symbols</h3>
107 *
108 * <p>A DecimalFormat object encapsulates a set of <em>properties</em> and a set of
109 * <em>symbols</em>. Grouping size, rounding mode, and affixes are examples of properties. Locale
110 * digits and the characters used for grouping and decimal separators are examples of symbols.
111 *
112 * <p>To set a custom set of symbols, use {@link #setDecimalFormatSymbols}. Use the various other
113 * setters in this class to set custom values for the properties.
114 *
115 * <h3>Rounding</h3>
116 *
117 * <p>DecimalFormat provides three main strategies to specify the position at which numbers should
118 * be rounded:
119 *
120 * <ol>
121 * <li><strong>Magnitude:</strong> Display a fixed number of fraction digits; this is the most
122 * common form.
123 * <li><strong>Increment:</strong> Round numbers to the closest multiple of a certain increment,
124 * such as 0.05. This is common in currencies.
125 * <li><strong>Significant Digits:</strong> Round numbers such that a fixed number of nonzero
126 * digits are shown. This is most common in scientific notation.
127 * </ol>
128 *
129 * <p>It is not possible to specify more than one rounding strategy. For example, setting a rounding
130 * increment in conjunction with significant digits results in undefined behavior.
131 *
132 * <p>It is also possible to specify the <em>rounding mode</em> to use. The default rounding mode is
133 * "half even", which rounds numbers to their closest increment, with ties broken in favor of
134 * trailing numbers being even. For more information, see {@link #setRoundingMode} and <a
135 * href="http://userguide.icu-project.org/formatparse/numbers/rounding-modes">the ICU User
136 * Guide</a>.
137 *
138 * <h3>Pattern Strings</h3>
139 *
140 * <p>A <em>pattern string</em> is a way to serialize some of the available properties for decimal
141 * formatting. However, not all properties are capable of being serialized into a pattern string;
142 * see {@link #applyPattern} for more information.
143 *
144 * <p>Most users should not need to interface with pattern strings directly.
145 *
146 * <p>ICU DecimalFormat aims to follow the specification for pattern strings in <a
147 * href="http://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns">UTS #35</a>.
148 * Refer to that specification for more information on pattern string syntax.
149 *
150 * <h4>Pattern String BNF</h4>
151 *
152 * The following BNF is used when parsing the pattern string into property values:
153 *
154 * <pre>
155 * pattern := subpattern (';' subpattern)?
156 * subpattern := prefix? number exponent? suffix?
157 * number := (integer ('.' fraction)?) | sigDigits
158 * prefix := '\u0000'..'\uFFFD' - specialCharacters
159 * suffix := '\u0000'..'\uFFFD' - specialCharacters
160 * integer := '#'* '0'* '0'
161 * fraction := '0'* '#'*
162 * sigDigits := '#'* '@' '@'* '#'*
163 * exponent := 'E' '+'? '0'* '0'
164 * padSpec := '*' padChar
165 * padChar := '\u0000'..'\uFFFD' - quote
166 *  
167 * Notation:
168 * X* 0 or more instances of X
169 * X? 0 or 1 instances of X
170 * X|Y either X or Y
171 * C..D any character from C up to D, inclusive
172 * S-T characters in S, except those in T
173 * </pre>
174 *
175 * <p>The first subpattern is for positive numbers. The second (optional) subpattern is for negative
176 * numbers.
177 *
178 * <p>Not indicated in the BNF syntax above:
179 *
180 * <ul>
181 * <li>The grouping separator ',' can occur inside the integer and sigDigits elements, between any
182 * two pattern characters of that element, as long as the integer or sigDigits element is not
183 * followed by the exponent element.
184 * <li>Two grouping intervals are recognized: That between the decimal point and the first
185 * grouping symbol, and that between the first and second grouping symbols. These intervals
186 * are identical in most locales, but in some locales they differ. For example, the pattern
187 * "#,##,###" formats the number 123456789 as "12,34,56,789".
188 * <li>The pad specifier <code>padSpec</code> may appear before the prefix, after the prefix,
189 * before the suffix, after the suffix, or not at all.
190 * <li>In place of '0', the digits '1' through '9' may be used to indicate a rounding increment.
191 * </ul>
192 *
193 * <h3>Parsing</h3>
194 *
195 * <p>DecimalFormat aims to be able to parse anything that it can output as a formatted string.
196 *
197 * <p>There are two primary parse modes: <em>lenient</em> and <em>strict</em>. Lenient mode should
198 * be used if the goal is to parse user input to a number; strict mode should be used if the goal is
199 * validation. The default is lenient mode. For more information, see {@link #setParseStrict}.
200 *
201 * <p><code>DecimalFormat</code> parses all Unicode characters that represent decimal digits, as
202 * defined by {@link UCharacter#digit}. In addition, <code>DecimalFormat</code> also recognizes as
203 * digits the ten consecutive characters starting with the localized zero digit defined in the
204 * {@link DecimalFormatSymbols} object. During formatting, the {@link DecimalFormatSymbols}-based
205 * digits are output.
206 *
207 * <p>Grouping separators are ignored in lenient mode (default). In strict mode, grouping separators
208 * must match the locale-specified grouping sizes.
209 *
210 * <p>When using {@link #parseCurrency}, all currencies are accepted, not just the currency
211 * currently set in the formatter. In addition, the formatter is able to parse every currency style
212 * format for a particular locale no matter which style the formatter is constructed with. For
213 * example, a formatter instance gotten from NumberFormat.getInstance(ULocale,
214 * NumberFormat.CURRENCYSTYLE) can parse both "USD1.00" and "3.00 US dollars".
215 *
216 * <p>Whitespace characters (lenient mode) and control characters (lenient and strict mode),
217 * collectively called "ignorables", do not need to match in identity or quantity between the
218 * pattern string and the input string. For example, the pattern "# %" matches "35 %" (with a single
219 * space), "35%" (with no space), "35 %" (with a non-breaking space), and "35 %" (with
220 * multiple spaces). Arbitrary ignorables are also allowed at boundaries between the parts of the
221 * number: prefix, number, exponent separator, and suffix. Ignorable whitespace characters are those
222 * having the Unicode "blank" property for regular expressions, defined in UTS #18 Annex C, which is
223 * "horizontal" whitespace, like spaces and tabs, but not "vertical" whitespace, like line breaks.
224 * Ignorable control characters are those in the Unicode set [:Default_Ignorable_Code_Point:].
225 *
226 * <p>If {@link #parse(String, ParsePosition)} fails to parse a string, it returns <code>null</code>
227 * and leaves the parse position unchanged. The convenience method {@link #parse(String)} indicates
228 * parse failure by throwing a {@link java.text.ParseException}.
229 *
230 * <p>Under the hood, a state table parsing engine is used. To debug a parsing failure during
231 * development, use the following pattern to print details about the state table transitions:
232 *
233 * <pre>
234 * ohos.global.icu.impl.number.Parse.DEBUGGING = true;
235 * df.parse("123.45", ppos);
236 * ohos.global.icu.impl.number.Parse.DEBUGGING = false;
237 * </pre>
238 *
239 * <h3>Thread Safety and Best Practices</h3>
240 *
241 * <p>Starting with ICU 59, instances of DecimalFormat are thread-safe.
242 *
243 * <p>Under the hood, DecimalFormat maintains an immutable formatter object that is rebuilt whenever
244 * any of the property setters are called. It is therefore best practice to call property setters
245 * only during construction and not when formatting numbers online.
246 *
247 * @see java.text.Format
248 * @see NumberFormat
249 */
250 public class DecimalFormat extends NumberFormat {
251
252 /** New serialization in ICU 59: declare different version from ICU 58. */
253 private static final long serialVersionUID = 864413376551465018L;
254
255 /**
256 * One non-transient field such that deserialization can determine the version of the class. This
257 * field has existed since the very earliest versions of DecimalFormat.
258 */
259 @SuppressWarnings("unused")
260 private final int serialVersionOnStream = 5;
261
262 //=====================================================================================//
263 // INSTANCE FIELDS //
264 //=====================================================================================//
265
266 // Fields are package-private, so that subclasses can use them.
267 // properties should be final, but clone won't work if we make it final.
268 // All fields are transient because custom serialization is used.
269
270 /**
271 * The property bag corresponding to user-specified settings and settings from the pattern string.
272 * In principle this should be final, but serialize and clone won't work if it is final. Does not
273 * need to be volatile because the reference never changes.
274 */
275 /* final */ transient DecimalFormatProperties properties;
276
277 /**
278 * The symbols for the current locale. Volatile because threads may read and write at the same
279 * time.
280 */
281 transient volatile DecimalFormatSymbols symbols;
282
283 /**
284 * The pre-computed formatter object. Setters cause this to be re-computed atomically. The {@link
285 * #format} method uses the formatter directly without needing to synchronize. Volatile because
286 * threads may read and write at the same time.
287 */
288 transient volatile LocalizedNumberFormatter formatter;
289
290 /**
291 * The effective properties as exported from the formatter object. Volatile because threads may
292 * read and write at the same time.
293 */
294 transient volatile DecimalFormatProperties exportedProperties;
295
296 transient volatile NumberParserImpl parser;
297 transient volatile NumberParserImpl currencyParser;
298
299 //=====================================================================================//
300 // CONSTRUCTORS //
301 //=====================================================================================//
302
303 /**
304 * Creates a DecimalFormat based on the number pattern and symbols for the default locale. This is
305 * a convenient way to obtain a DecimalFormat instance when internationalization is not the main
306 * concern.
307 *
308 * <p>Most users should call the factory methods on NumberFormat, such as {@link
309 * NumberFormat#getNumberInstance}, which return localized formatter objects, instead of the
310 * DecimalFormat constructors.
311 *
312 * @see NumberFormat#getInstance
313 * @see NumberFormat#getNumberInstance
314 * @see NumberFormat#getCurrencyInstance
315 * @see NumberFormat#getPercentInstance
316 * @see Category#FORMAT
317 */
DecimalFormat()318 public DecimalFormat() {
319 // Use the locale's default pattern
320 ULocale def = ULocale.getDefault(ULocale.Category.FORMAT);
321 String pattern = getPattern(def, NumberFormat.NUMBERSTYLE);
322 symbols = getDefaultSymbols();
323 properties = new DecimalFormatProperties();
324 exportedProperties = new DecimalFormatProperties();
325 // Regression: ignore pattern rounding information if the pattern has currency symbols.
326 setPropertiesFromPattern(pattern, PatternStringParser.IGNORE_ROUNDING_IF_CURRENCY);
327 refreshFormatter();
328 }
329
330 /**
331 * Creates a DecimalFormat based on the given pattern, using symbols for the default locale. This
332 * is a convenient way to obtain a DecimalFormat instance when internationalization is not the
333 * main concern.
334 *
335 * <p>Most users should call the factory methods on NumberFormat, such as {@link
336 * NumberFormat#getNumberInstance}, which return localized formatter objects, instead of the
337 * DecimalFormat constructors.
338 *
339 * @param pattern A pattern string such as "#,##0.00" conforming to <a
340 * href="http://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns">UTS
341 * #35</a>.
342 * @throws IllegalArgumentException if the given pattern is invalid.
343 * @see NumberFormat#getInstance
344 * @see NumberFormat#getNumberInstance
345 * @see NumberFormat#getCurrencyInstance
346 * @see NumberFormat#getPercentInstance
347 * @see Category#FORMAT
348 */
DecimalFormat(String pattern)349 public DecimalFormat(String pattern) {
350 symbols = getDefaultSymbols();
351 properties = new DecimalFormatProperties();
352 exportedProperties = new DecimalFormatProperties();
353 // Regression: ignore pattern rounding information if the pattern has currency symbols.
354 setPropertiesFromPattern(pattern, PatternStringParser.IGNORE_ROUNDING_IF_CURRENCY);
355 refreshFormatter();
356 }
357
358 /**
359 * Creates a DecimalFormat based on the given pattern and symbols. Use this constructor if you
360 * want complete control over the behavior of the formatter.
361 *
362 * <p>Most users should call the factory methods on NumberFormat, such as {@link
363 * NumberFormat#getNumberInstance}, which return localized formatter objects, instead of the
364 * DecimalFormat constructors.
365 *
366 * @param pattern A pattern string such as "#,##0.00" conforming to <a
367 * href="http://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns">UTS
368 * #35</a>.
369 * @param symbols The set of symbols to be used.
370 * @exception IllegalArgumentException if the given pattern is invalid
371 * @see NumberFormat#getInstance
372 * @see NumberFormat#getNumberInstance
373 * @see NumberFormat#getCurrencyInstance
374 * @see NumberFormat#getPercentInstance
375 * @see DecimalFormatSymbols
376 */
DecimalFormat(String pattern, DecimalFormatSymbols symbols)377 public DecimalFormat(String pattern, DecimalFormatSymbols symbols) {
378 this.symbols = (DecimalFormatSymbols) symbols.clone();
379 properties = new DecimalFormatProperties();
380 exportedProperties = new DecimalFormatProperties();
381 // Regression: ignore pattern rounding information if the pattern has currency symbols.
382 setPropertiesFromPattern(pattern, PatternStringParser.IGNORE_ROUNDING_IF_CURRENCY);
383 refreshFormatter();
384 }
385
386 /**
387 * Creates a DecimalFormat based on the given pattern and symbols, with additional control over
388 * the behavior of currency. The style argument determines whether currency rounding rules should
389 * override the pattern, and the {@link CurrencyPluralInfo} object is used for customizing the
390 * plural forms used for currency long names.
391 *
392 * <p>Most users should call the factory methods on NumberFormat, such as {@link
393 * NumberFormat#getNumberInstance}, which return localized formatter objects, instead of the
394 * DecimalFormat constructors.
395 *
396 * @param pattern a non-localized pattern string
397 * @param symbols the set of symbols to be used
398 * @param infoInput the information used for currency plural format, including currency plural
399 * patterns and plural rules.
400 * @param style the decimal formatting style, it is one of the following values:
401 * NumberFormat.NUMBERSTYLE; NumberFormat.CURRENCYSTYLE; NumberFormat.PERCENTSTYLE;
402 * NumberFormat.SCIENTIFICSTYLE; NumberFormat.INTEGERSTYLE; NumberFormat.ISOCURRENCYSTYLE;
403 * NumberFormat.PLURALCURRENCYSTYLE;
404 */
DecimalFormat( String pattern, DecimalFormatSymbols symbols, CurrencyPluralInfo infoInput, int style)405 public DecimalFormat(
406 String pattern, DecimalFormatSymbols symbols, CurrencyPluralInfo infoInput, int style) {
407 this(pattern, symbols, style);
408 properties.setCurrencyPluralInfo(infoInput);
409 refreshFormatter();
410 }
411
412 /** Package-private constructor used by NumberFormat. */
DecimalFormat(String pattern, DecimalFormatSymbols symbols, int choice)413 DecimalFormat(String pattern, DecimalFormatSymbols symbols, int choice) {
414 this.symbols = (DecimalFormatSymbols) symbols.clone();
415 properties = new DecimalFormatProperties();
416 exportedProperties = new DecimalFormatProperties();
417 // If choice is a currency type, ignore the rounding information.
418 if (choice == CURRENCYSTYLE
419 || choice == ISOCURRENCYSTYLE
420 || choice == ACCOUNTINGCURRENCYSTYLE
421 || choice == CASHCURRENCYSTYLE
422 || choice == STANDARDCURRENCYSTYLE
423 || choice == PLURALCURRENCYSTYLE) {
424 setPropertiesFromPattern(pattern, PatternStringParser.IGNORE_ROUNDING_ALWAYS);
425 } else {
426 setPropertiesFromPattern(pattern, PatternStringParser.IGNORE_ROUNDING_IF_CURRENCY);
427 }
428 refreshFormatter();
429 }
430
getDefaultSymbols()431 private static DecimalFormatSymbols getDefaultSymbols() {
432 return DecimalFormatSymbols.getInstance();
433 }
434
435 /**
436 * Parses the given pattern string and overwrites the settings specified in the pattern string.
437 * The properties corresponding to the following setters are overwritten, either with their
438 * default values or with the value specified in the pattern string:
439 *
440 * <ol>
441 * <li>{@link #setDecimalSeparatorAlwaysShown}
442 * <li>{@link #setExponentSignAlwaysShown}
443 * <li>{@link #setFormatWidth}
444 * <li>{@link #setGroupingSize}
445 * <li>{@link #setMultiplier} (percent/permille)
446 * <li>{@link #setMaximumFractionDigits}
447 * <li>{@link #setMaximumIntegerDigits}
448 * <li>{@link #setMaximumSignificantDigits}
449 * <li>{@link #setMinimumExponentDigits}
450 * <li>{@link #setMinimumFractionDigits}
451 * <li>{@link #setMinimumIntegerDigits}
452 * <li>{@link #setMinimumSignificantDigits}
453 * <li>{@link #setPadPosition}
454 * <li>{@link #setPadCharacter}
455 * <li>{@link #setRoundingIncrement}
456 * <li>{@link #setSecondaryGroupingSize}
457 * </ol>
458 *
459 * All other settings remain untouched.
460 *
461 * <p>For more information on pattern strings, see <a
462 * href="http://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns">UTS #35</a>.
463 */
applyPattern(String pattern)464 public synchronized void applyPattern(String pattern) {
465 setPropertiesFromPattern(pattern, PatternStringParser.IGNORE_ROUNDING_NEVER);
466 // Backwards compatibility: clear out user-specified prefix and suffix,
467 // as well as CurrencyPluralInfo.
468 properties.setPositivePrefix(null);
469 properties.setNegativePrefix(null);
470 properties.setPositiveSuffix(null);
471 properties.setNegativeSuffix(null);
472 properties.setCurrencyPluralInfo(null);
473 refreshFormatter();
474 }
475
476 /**
477 * Converts the given string to standard notation and then parses it using {@link #applyPattern}.
478 * This method is provided for backwards compatibility and should not be used in new projects.
479 *
480 * <p>Localized notation means that instead of using generic placeholders in the pattern, you use
481 * the corresponding locale-specific characters instead. For example, in locale <em>fr-FR</em>,
482 * the period in the pattern "0.000" means "decimal" in standard notation (as it does in every
483 * other locale), but it means "grouping" in localized notation.
484 *
485 * @param localizedPattern The pattern string in localized notation.
486 */
applyLocalizedPattern(String localizedPattern)487 public synchronized void applyLocalizedPattern(String localizedPattern) {
488 String pattern = PatternStringUtils.convertLocalized(localizedPattern, symbols, false);
489 applyPattern(pattern);
490 }
491
492 //=====================================================================================//
493 // CLONE AND SERIALIZE //
494 //=====================================================================================//
495
496 /***/
497 @Override
clone()498 public Object clone() {
499 DecimalFormat other = (DecimalFormat) super.clone();
500 other.symbols = (DecimalFormatSymbols) symbols.clone();
501 other.properties = properties.clone();
502 other.exportedProperties = new DecimalFormatProperties();
503 other.refreshFormatter();
504 return other;
505 }
506
507 /**
508 * Custom serialization: save property bag and symbols; the formatter object can be re-created
509 * from just that amount of information.
510 */
writeObject(ObjectOutputStream oos)511 private synchronized void writeObject(ObjectOutputStream oos) throws IOException {
512 // ICU 59 custom serialization.
513 // Write class metadata and serialVersionOnStream field:
514 oos.defaultWriteObject();
515 // Extra int for possible future use:
516 oos.writeInt(0);
517 // 1) Property Bag
518 oos.writeObject(properties);
519 // 2) DecimalFormatSymbols
520 oos.writeObject(symbols);
521 }
522
523 /**
524 * Custom serialization: re-create object from serialized property bag and symbols. Also supports
525 * reading from the legacy (pre-ICU4J 59) format and converting it to the new form.
526 */
readObject(ObjectInputStream ois)527 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
528 ObjectInputStream.GetField fieldGetter = ois.readFields();
529 ObjectStreamField[] serializedFields = fieldGetter.getObjectStreamClass().getFields();
530 int serialVersion = fieldGetter.get("serialVersionOnStream", -1);
531
532 if (serialVersion > 5) {
533 throw new IOException(
534 "Cannot deserialize newer ohos.global.icu.text.DecimalFormat (v" + serialVersion + ")");
535 } else if (serialVersion == 5) {
536 ///// ICU 59+ SERIALIZATION FORMAT /////
537 // We expect this field and no other fields:
538 if (serializedFields.length > 1) {
539 throw new IOException("Too many fields when reading serial version 5");
540 }
541 // Extra int for possible future use:
542 ois.readInt();
543 // 1) Property Bag
544 Object serializedProperties = ois.readObject();
545 if (serializedProperties instanceof DecimalFormatProperties) {
546 // ICU 60+
547 properties = (DecimalFormatProperties) serializedProperties;
548 } else {
549 // ICU 59
550 properties = ((ohos.global.icu.impl.number.Properties) serializedProperties).getInstance();
551 }
552 // 2) DecimalFormatSymbols
553 symbols = (DecimalFormatSymbols) ois.readObject();
554 // Re-build transient fields
555 exportedProperties = new DecimalFormatProperties();
556 refreshFormatter();
557 } else {
558 ///// LEGACY SERIALIZATION FORMAT /////
559 properties = new DecimalFormatProperties();
560 // Loop through the fields. Not all fields necessarily exist in the serialization.
561 String pp = null, ppp = null, ps = null, psp = null;
562 String np = null, npp = null, ns = null, nsp = null;
563 for (ObjectStreamField field : serializedFields) {
564 String name = field.getName();
565 if (name.equals("decimalSeparatorAlwaysShown")) {
566 setDecimalSeparatorAlwaysShown(fieldGetter.get("decimalSeparatorAlwaysShown", false));
567 } else if (name.equals("exponentSignAlwaysShown")) {
568 setExponentSignAlwaysShown(fieldGetter.get("exponentSignAlwaysShown", false));
569 } else if (name.equals("formatWidth")) {
570 setFormatWidth(fieldGetter.get("formatWidth", 0));
571 } else if (name.equals("groupingSize")) {
572 setGroupingSize(fieldGetter.get("groupingSize", (byte) 3));
573 } else if (name.equals("groupingSize2")) {
574 setSecondaryGroupingSize(fieldGetter.get("groupingSize2", (byte) 0));
575 } else if (name.equals("maxSignificantDigits")) {
576 setMaximumSignificantDigits(fieldGetter.get("maxSignificantDigits", 6));
577 } else if (name.equals("minExponentDigits")) {
578 setMinimumExponentDigits(fieldGetter.get("minExponentDigits", (byte) 0));
579 } else if (name.equals("minSignificantDigits")) {
580 setMinimumSignificantDigits(fieldGetter.get("minSignificantDigits", 1));
581 } else if (name.equals("multiplier")) {
582 setMultiplier(fieldGetter.get("multiplier", 1));
583 } else if (name.equals("pad")) {
584 setPadCharacter(fieldGetter.get("pad", '\u0020'));
585 } else if (name.equals("padPosition")) {
586 setPadPosition(fieldGetter.get("padPosition", 0));
587 } else if (name.equals("parseBigDecimal")) {
588 setParseBigDecimal(fieldGetter.get("parseBigDecimal", false));
589 } else if (name.equals("parseRequireDecimalPoint")) {
590 setDecimalPatternMatchRequired(fieldGetter.get("parseRequireDecimalPoint", false));
591 } else if (name.equals("roundingMode")) {
592 setRoundingMode(fieldGetter.get("roundingMode", 0));
593 } else if (name.equals("useExponentialNotation")) {
594 setScientificNotation(fieldGetter.get("useExponentialNotation", false));
595 } else if (name.equals("useSignificantDigits")) {
596 setSignificantDigitsUsed(fieldGetter.get("useSignificantDigits", false));
597 } else if (name.equals("currencyPluralInfo")) {
598 setCurrencyPluralInfo((CurrencyPluralInfo) fieldGetter.get("currencyPluralInfo", null));
599 } else if (name.equals("mathContext")) {
600 setMathContextICU((MathContext) fieldGetter.get("mathContext", null));
601 } else if (name.equals("negPrefixPattern")) {
602 npp = (String) fieldGetter.get("negPrefixPattern", null);
603 } else if (name.equals("negSuffixPattern")) {
604 nsp = (String) fieldGetter.get("negSuffixPattern", null);
605 } else if (name.equals("negativePrefix")) {
606 np = (String) fieldGetter.get("negativePrefix", null);
607 } else if (name.equals("negativeSuffix")) {
608 ns = (String) fieldGetter.get("negativeSuffix", null);
609 } else if (name.equals("posPrefixPattern")) {
610 ppp = (String) fieldGetter.get("posPrefixPattern", null);
611 } else if (name.equals("posSuffixPattern")) {
612 psp = (String) fieldGetter.get("posSuffixPattern", null);
613 } else if (name.equals("positivePrefix")) {
614 pp = (String) fieldGetter.get("positivePrefix", null);
615 } else if (name.equals("positiveSuffix")) {
616 ps = (String) fieldGetter.get("positiveSuffix", null);
617 } else if (name.equals("roundingIncrement")) {
618 setRoundingIncrement((java.math.BigDecimal) fieldGetter.get("roundingIncrement", null));
619 } else if (name.equals("symbols")) {
620 setDecimalFormatSymbols((DecimalFormatSymbols) fieldGetter.get("symbols", null));
621 } else {
622 // The following fields are ignored:
623 // "PARSE_MAX_EXPONENT"
624 // "currencySignCount"
625 // "style"
626 // "attributes"
627 // "currencyChoice"
628 // "formatPattern"
629 // "currencyUsage" => ignore this because the old code puts currencyUsage directly into min/max fraction.
630 }
631 }
632 // Resolve affixes
633 if (npp == null) {
634 properties.setNegativePrefix(np);
635 } else {
636 properties.setNegativePrefixPattern(npp);
637 }
638 if (nsp == null) {
639 properties.setNegativeSuffix(ns);
640 } else {
641 properties.setNegativeSuffixPattern(nsp);
642 }
643 if (ppp == null) {
644 properties.setPositivePrefix(pp);
645 } else {
646 properties.setPositivePrefixPattern(ppp);
647 }
648 if (psp == null) {
649 properties.setPositiveSuffix(ps);
650 } else {
651 properties.setPositiveSuffixPattern(psp);
652 }
653 // Extract values from parent NumberFormat class. Have to use reflection here.
654 java.lang.reflect.Field getter;
655 try {
656 getter = NumberFormat.class.getDeclaredField("groupingUsed");
657 getter.setAccessible(true);
658 setGroupingUsed((Boolean) getter.get(this));
659 getter = NumberFormat.class.getDeclaredField("parseIntegerOnly");
660 getter.setAccessible(true);
661 setParseIntegerOnly((Boolean) getter.get(this));
662 getter = NumberFormat.class.getDeclaredField("maximumIntegerDigits");
663 getter.setAccessible(true);
664 setMaximumIntegerDigits((Integer) getter.get(this));
665 getter = NumberFormat.class.getDeclaredField("minimumIntegerDigits");
666 getter.setAccessible(true);
667 setMinimumIntegerDigits((Integer) getter.get(this));
668 getter = NumberFormat.class.getDeclaredField("maximumFractionDigits");
669 getter.setAccessible(true);
670 setMaximumFractionDigits((Integer) getter.get(this));
671 getter = NumberFormat.class.getDeclaredField("minimumFractionDigits");
672 getter.setAccessible(true);
673 setMinimumFractionDigits((Integer) getter.get(this));
674 getter = NumberFormat.class.getDeclaredField("currency");
675 getter.setAccessible(true);
676 setCurrency((Currency) getter.get(this));
677 getter = NumberFormat.class.getDeclaredField("parseStrict");
678 getter.setAccessible(true);
679 setParseStrict((Boolean) getter.get(this));
680 } catch (IllegalArgumentException e) {
681 throw new IOException(e);
682 } catch (IllegalAccessException e) {
683 throw new IOException(e);
684 } catch (NoSuchFieldException e) {
685 throw new IOException(e);
686 } catch (SecurityException e) {
687 throw new IOException(e);
688 }
689 // Finish initialization
690 if (symbols == null) {
691 symbols = getDefaultSymbols();
692 }
693 exportedProperties = new DecimalFormatProperties();
694 refreshFormatter();
695 }
696 }
697
698 //=====================================================================================//
699 // FORMAT AND PARSE APIS //
700 //=====================================================================================//
701
702 /**
703 * {@inheritDoc}
704 */
705 @Override
format(double number, StringBuffer result, FieldPosition fieldPosition)706 public StringBuffer format(double number, StringBuffer result, FieldPosition fieldPosition) {
707 DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(number);
708 FormattedStringBuilder string = new FormattedStringBuilder();
709 formatter.formatImpl(dq, string);
710 fieldPositionHelper(dq, string, fieldPosition, result.length());
711 Utility.appendTo(string, result);
712 return result;
713 }
714
715 /**
716 * {@inheritDoc}
717 */
718 @Override
format(long number, StringBuffer result, FieldPosition fieldPosition)719 public StringBuffer format(long number, StringBuffer result, FieldPosition fieldPosition) {
720 DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(number);
721 FormattedStringBuilder string = new FormattedStringBuilder();
722 formatter.formatImpl(dq, string);
723 fieldPositionHelper(dq, string, fieldPosition, result.length());
724 Utility.appendTo(string, result);
725 return result;
726 }
727
728 /**
729 * {@inheritDoc}
730 */
731 @Override
format(BigInteger number, StringBuffer result, FieldPosition fieldPosition)732 public StringBuffer format(BigInteger number, StringBuffer result, FieldPosition fieldPosition) {
733 DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(number);
734 FormattedStringBuilder string = new FormattedStringBuilder();
735 formatter.formatImpl(dq, string);
736 fieldPositionHelper(dq, string, fieldPosition, result.length());
737 Utility.appendTo(string, result);
738 return result;
739 }
740
741 /**
742 * {@inheritDoc}
743 */
744 @Override
format( java.math.BigDecimal number, StringBuffer result, FieldPosition fieldPosition)745 public StringBuffer format(
746 java.math.BigDecimal number, StringBuffer result, FieldPosition fieldPosition) {
747 DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(number);
748 FormattedStringBuilder string = new FormattedStringBuilder();
749 formatter.formatImpl(dq, string);
750 fieldPositionHelper(dq, string, fieldPosition, result.length());
751 Utility.appendTo(string, result);
752 return result;
753 }
754
755 /**
756 * {@inheritDoc}
757 */
758 @Override
format(BigDecimal number, StringBuffer result, FieldPosition fieldPosition)759 public StringBuffer format(BigDecimal number, StringBuffer result, FieldPosition fieldPosition) {
760 DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(number);
761 FormattedStringBuilder string = new FormattedStringBuilder();
762 formatter.formatImpl(dq, string);
763 fieldPositionHelper(dq, string, fieldPosition, result.length());
764 Utility.appendTo(string, result);
765 return result;
766 }
767
768 /**
769 * {@inheritDoc}
770 */
771 @Override
formatToCharacterIterator(Object obj)772 public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
773 if (!(obj instanceof Number)) throw new IllegalArgumentException();
774 Number number = (Number) obj;
775 FormattedNumber output = formatter.format(number);
776 return output.toCharacterIterator();
777 }
778
779 /**
780 * {@inheritDoc}
781 */
782 @Override
format(CurrencyAmount currAmt, StringBuffer result, FieldPosition fieldPosition)783 public StringBuffer format(CurrencyAmount currAmt, StringBuffer result, FieldPosition fieldPosition) {
784 // We need to make localSymbols in order for monetary symbols to be initialized.
785 // Also, bypass the CurrencyAmount override of LocalizedNumberFormatter#format,
786 // because its caching mechanism will not provide any benefit here.
787 DecimalFormatSymbols localSymbols = (DecimalFormatSymbols) symbols.clone();
788 localSymbols.setCurrency(currAmt.getCurrency());
789
790 DecimalQuantity dq = new DecimalQuantity_DualStorageBCD(currAmt.getNumber());
791 FormattedStringBuilder string = new FormattedStringBuilder();
792 formatter.symbols(localSymbols)
793 .unit(currAmt.getCurrency())
794 .formatImpl(dq, string);
795 fieldPositionHelper(dq, string, fieldPosition, result.length());
796 Utility.appendTo(string, result);
797 return result;
798 }
799
800 /**
801 * {@inheritDoc}
802 */
803 @Override
parse(String text, ParsePosition parsePosition)804 public Number parse(String text, ParsePosition parsePosition) {
805 if (text == null) {
806 throw new IllegalArgumentException("Text cannot be null");
807 }
808 if (parsePosition == null) {
809 parsePosition = new ParsePosition(0);
810 }
811 if (parsePosition.getIndex() < 0) {
812 throw new IllegalArgumentException("Cannot start parsing at a negative offset");
813 }
814 if (parsePosition.getIndex() >= text.length()) {
815 // For backwards compatibility, this is not an exception, just an empty result.
816 return null;
817 }
818
819 ParsedNumber result = new ParsedNumber();
820 // Note: if this is a currency instance, currencies will be matched despite the fact that we are not in the
821 // parseCurrency method (backwards compatibility)
822 int startIndex = parsePosition.getIndex();
823 NumberParserImpl parser = getParser();
824 parser.parse(text, startIndex, true, result);
825 if (result.success()) {
826 parsePosition.setIndex(result.charEnd);
827 // TODO: Accessing properties here is technically not thread-safe
828 Number number = result.getNumber(parser.getParseFlags());
829 // Backwards compatibility: return ohos.global.icu.math.BigDecimal
830 if (number instanceof java.math.BigDecimal) {
831 number = safeConvertBigDecimal((java.math.BigDecimal) number);
832 }
833 return number;
834 } else {
835 parsePosition.setErrorIndex(startIndex + result.charEnd);
836 return null;
837 }
838 }
839
840 /**
841 * {@inheritDoc}
842 */
843 @Override
parseCurrency(CharSequence text, ParsePosition parsePosition)844 public CurrencyAmount parseCurrency(CharSequence text, ParsePosition parsePosition) {
845 if (text == null) {
846 throw new IllegalArgumentException("Text cannot be null");
847 }
848 if (parsePosition == null) {
849 parsePosition = new ParsePosition(0);
850 }
851 if (parsePosition.getIndex() < 0) {
852 throw new IllegalArgumentException("Cannot start parsing at a negative offset");
853 }
854 if (parsePosition.getIndex() >= text.length()) {
855 // For backwards compatibility, this is not an exception, just an empty result.
856 return null;
857 }
858
859 ParsedNumber result = new ParsedNumber();
860 int startIndex = parsePosition.getIndex();
861 NumberParserImpl parser = getCurrencyParser();
862 parser.parse(text.toString(), startIndex, true, result);
863 if (result.success()) {
864 parsePosition.setIndex(result.charEnd);
865 // TODO: Accessing properties here is technically not thread-safe
866 Number number = result.getNumber(parser.getParseFlags());
867 // Backwards compatibility: return ohos.global.icu.math.BigDecimal
868 if (number instanceof java.math.BigDecimal) {
869 number = safeConvertBigDecimal((java.math.BigDecimal) number);
870 }
871 Currency currency = Currency.getInstance(result.currencyCode);
872 return new CurrencyAmount(number, currency);
873 } else {
874 parsePosition.setErrorIndex(startIndex + result.charEnd);
875 return null;
876 }
877 }
878
879 //=====================================================================================//
880 // GETTERS AND SETTERS //
881 //=====================================================================================//
882
883 /**
884 * Returns a copy of the decimal format symbols used by this formatter.
885 *
886 * @return desired DecimalFormatSymbols
887 * @see DecimalFormatSymbols
888 */
getDecimalFormatSymbols()889 public synchronized DecimalFormatSymbols getDecimalFormatSymbols() {
890 return (DecimalFormatSymbols) symbols.clone();
891 }
892
893 /**
894 * Sets the decimal format symbols used by this formatter. The formatter uses a copy of the
895 * provided symbols.
896 *
897 * @param newSymbols desired DecimalFormatSymbols
898 * @see DecimalFormatSymbols
899 */
setDecimalFormatSymbols(DecimalFormatSymbols newSymbols)900 public synchronized void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
901 symbols = (DecimalFormatSymbols) newSymbols.clone();
902 refreshFormatter();
903 }
904
905 /**
906 * <strong>Affixes:</strong> Gets the positive prefix string currently being used to format
907 * numbers.
908 *
909 * <p>If the affix was specified via the pattern, the string returned by this method will have
910 * locale symbols substituted in place of special characters according to the LDML specification.
911 * If the affix was specified via {@link #setPositivePrefix}, the string will be returned
912 * literally.
913 *
914 * @return The string being prepended to positive numbers.
915 */
getPositivePrefix()916 public synchronized String getPositivePrefix() {
917 return formatter.getAffixImpl(true, false);
918 }
919
920 /**
921 * <strong>Affixes:</strong> Sets the string to prepend to positive numbers. For example, if you
922 * set the value "#", then the number 123 will be formatted as "#123" in the locale
923 * <em>en-US</em>.
924 *
925 * <p>Using this method overrides the affix specified via the pattern, and unlike the pattern, the
926 * string given to this method will be interpreted literally WITHOUT locale symbol substitutions.
927 *
928 * @param prefix The literal string to prepend to positive numbers.
929 */
setPositivePrefix(String prefix)930 public synchronized void setPositivePrefix(String prefix) {
931 if (prefix == null) {
932 throw new NullPointerException();
933 }
934 properties.setPositivePrefix(prefix);
935 refreshFormatter();
936 }
937
938 /**
939 * <strong>Affixes:</strong> Gets the negative prefix string currently being used to format
940 * numbers.
941 *
942 * <p>If the affix was specified via the pattern, the string returned by this method will have
943 * locale symbols substituted in place of special characters according to the LDML specification.
944 * If the affix was specified via {@link #setNegativePrefix}, the string will be returned
945 * literally.
946 *
947 * @return The string being prepended to negative numbers.
948 */
getNegativePrefix()949 public synchronized String getNegativePrefix() {
950 return formatter.getAffixImpl(true, true);
951 }
952
953 /**
954 * <strong>Affixes:</strong> Sets the string to prepend to negative numbers. For example, if you
955 * set the value "#", then the number -123 will be formatted as "#123" in the locale
956 * <em>en-US</em> (overriding the implicit default '-' in the pattern).
957 *
958 * <p>Using this method overrides the affix specified via the pattern, and unlike the pattern, the
959 * string given to this method will be interpreted literally WITHOUT locale symbol substitutions.
960 *
961 * @param prefix The literal string to prepend to negative numbers.
962 */
setNegativePrefix(String prefix)963 public synchronized void setNegativePrefix(String prefix) {
964 if (prefix == null) {
965 throw new NullPointerException();
966 }
967 properties.setNegativePrefix(prefix);
968 refreshFormatter();
969 }
970
971 /**
972 * <strong>Affixes:</strong> Gets the positive suffix string currently being used to format
973 * numbers.
974 *
975 * <p>If the affix was specified via the pattern, the string returned by this method will have
976 * locale symbols substituted in place of special characters according to the LDML specification.
977 * If the affix was specified via {@link #setPositiveSuffix}, the string will be returned
978 * literally.
979 *
980 * @return The string being appended to positive numbers.
981 */
getPositiveSuffix()982 public synchronized String getPositiveSuffix() {
983 return formatter.getAffixImpl(false, false);
984 }
985
986 /**
987 * <strong>Affixes:</strong> Sets the string to append to positive numbers. For example, if you
988 * set the value "#", then the number 123 will be formatted as "123#" in the locale
989 * <em>en-US</em>.
990 *
991 * <p>Using this method overrides the affix specified via the pattern, and unlike the pattern, the
992 * string given to this method will be interpreted literally WITHOUT locale symbol substitutions.
993 *
994 * @param suffix The literal string to append to positive numbers.
995 */
setPositiveSuffix(String suffix)996 public synchronized void setPositiveSuffix(String suffix) {
997 if (suffix == null) {
998 throw new NullPointerException();
999 }
1000 properties.setPositiveSuffix(suffix);
1001 refreshFormatter();
1002 }
1003
1004 /**
1005 * <strong>Affixes:</strong> Gets the negative suffix string currently being used to format
1006 * numbers.
1007 *
1008 * <p>If the affix was specified via the pattern, the string returned by this method will have
1009 * locale symbols substituted in place of special characters according to the LDML specification.
1010 * If the affix was specified via {@link #setNegativeSuffix}, the string will be returned
1011 * literally.
1012 *
1013 * @return The string being appended to negative numbers.
1014 */
getNegativeSuffix()1015 public synchronized String getNegativeSuffix() {
1016 return formatter.getAffixImpl(false, true);
1017 }
1018
1019 /**
1020 * <strong>Affixes:</strong> Sets the string to append to negative numbers. For example, if you
1021 * set the value "#", then the number 123 will be formatted as "123#" in the locale
1022 * <em>en-US</em>.
1023 *
1024 * <p>Using this method overrides the affix specified via the pattern, and unlike the pattern, the
1025 * string given to this method will be interpreted literally WITHOUT locale symbol substitutions.
1026 *
1027 * @param suffix The literal string to append to negative numbers.
1028 */
setNegativeSuffix(String suffix)1029 public synchronized void setNegativeSuffix(String suffix) {
1030 if (suffix == null) {
1031 throw new NullPointerException();
1032 }
1033 properties.setNegativeSuffix(suffix);
1034 refreshFormatter();
1035 }
1036
1037 /**
1038 * <strong>[icu]</strong> Returns whether the sign is being shown on positive numbers.
1039 *
1040 * @return Whether the sign is shown on positive numbers and zero.
1041 * @see #setSignAlwaysShown
1042 */
isSignAlwaysShown()1043 public synchronized boolean isSignAlwaysShown() {
1044 // This is not in the exported properties
1045 return properties.getSignAlwaysShown();
1046 }
1047
1048 /**
1049 * Sets whether to always shown the plus sign ('+' in <em>en</em>) on positive numbers. The rules
1050 * in UTS #35 section 3.2.1 will be followed to ensure a locale-aware placement of the sign.
1051 *
1052 * <p>More specifically, the following strategy will be used to place the plus sign:
1053 *
1054 * <ol>
1055 * <li><em>Patterns without a negative subpattern:</em> The locale's plus sign will be prepended
1056 * to the positive prefix.
1057 * <li><em>Patterns with a negative subpattern without a '-' sign (e.g., accounting):</em> The
1058 * locale's plus sign will be prepended to the positive prefix, as in case 1.
1059 * <li><em>Patterns with a negative subpattern that has a '-' sign:</em> The locale's plus sign
1060 * will substitute the '-' in the negative subpattern. The positive subpattern will be
1061 * unused.
1062 * </ol>
1063 *
1064 * This method is designed to be used <em>instead of</em> applying a pattern containing an
1065 * explicit plus sign, such as "+0;-0". The behavior when combining this method with explicit plus
1066 * signs in the pattern is undefined.
1067 *
1068 * @param value true to always show a sign; false to hide the sign on positive numbers and zero.
1069 */
setSignAlwaysShown(boolean value)1070 public synchronized void setSignAlwaysShown(boolean value) {
1071 properties.setSignAlwaysShown(value);
1072 refreshFormatter();
1073 }
1074
1075 /**
1076 * Returns the multiplier being applied to numbers before they are formatted.
1077 *
1078 * @see #setMultiplier
1079 */
getMultiplier()1080 public synchronized int getMultiplier() {
1081 if (properties.getMultiplier() != null) {
1082 return properties.getMultiplier().intValue();
1083 } else {
1084 return (int) Math.pow(10, properties.getMagnitudeMultiplier());
1085 }
1086 }
1087
1088 /**
1089 * Sets a number that will be used to multiply all numbers prior to formatting. For example, when
1090 * formatting percents, a multiplier of 100 can be used.
1091 *
1092 * <p>If a percent or permille sign is specified in the pattern, the multiplier is automatically
1093 * set to 100 or 1000, respectively.
1094 *
1095 * <p>If the number specified here is a power of 10, a more efficient code path will be used.
1096 *
1097 * @param multiplier The number by which all numbers passed to {@link #format} will be multiplied.
1098 * @throws IllegalArgumentException If the given multiplier is zero.
1099 * @throws ArithmeticException when inverting multiplier produces a non-terminating decimal result
1100 * in conjunction with MathContext of unlimited precision.
1101 */
setMultiplier(int multiplier)1102 public synchronized void setMultiplier(int multiplier) {
1103 if (multiplier == 0) {
1104 throw new IllegalArgumentException("Multiplier must be nonzero.");
1105 }
1106
1107 // Try to convert to a magnitude multiplier first
1108 int delta = 0;
1109 int value = multiplier;
1110 while (value != 1) {
1111 delta++;
1112 int temp = value / 10;
1113 if (temp * 10 != value) {
1114 delta = -1;
1115 break;
1116 }
1117 value = temp;
1118 }
1119 if (delta != -1) {
1120 properties.setMagnitudeMultiplier(delta);
1121 properties.setMultiplier(null);
1122 } else {
1123 properties.setMagnitudeMultiplier(0);
1124 properties.setMultiplier(java.math.BigDecimal.valueOf(multiplier));
1125 }
1126 refreshFormatter();
1127 }
1128
1129 /**
1130 * <strong>[icu]</strong> Returns the increment to which numbers are being rounded.
1131 *
1132 * @see #setRoundingIncrement
1133 */
getRoundingIncrement()1134 public synchronized java.math.BigDecimal getRoundingIncrement() {
1135 return exportedProperties.getRoundingIncrement();
1136 }
1137
1138 /**
1139 * <strong>[icu]</strong> <strong>Rounding and Digit Limits:</strong> Sets an increment, or interval, to which
1140 * numbers are rounded. For example, a rounding increment of 0.05 will cause the number 1.23 to be
1141 * rounded to 1.25 in the default rounding mode.
1142 *
1143 * <p>The rounding increment can be specified via the pattern string: for example, the pattern
1144 * "#,##0.05" encodes a rounding increment of 0.05.
1145 *
1146 * <p>The rounding increment is applied <em>after</em> any multipliers might take effect; for
1147 * example, in scientific notation or when {@link #setMultiplier} is used.
1148 *
1149 * <p>See {@link #setMaximumFractionDigits} and {@link #setMaximumSignificantDigits} for two other
1150 * ways of specifying rounding strategies.
1151 *
1152 * @param increment The increment to which numbers are to be rounded.
1153 * @see #setRoundingMode
1154 * @see #setMaximumFractionDigits
1155 * @see #setMaximumSignificantDigits
1156 */
setRoundingIncrement(java.math.BigDecimal increment)1157 public synchronized void setRoundingIncrement(java.math.BigDecimal increment) {
1158 // Backwards compatibility: ignore rounding increment if zero,
1159 // and instead set maximum fraction digits.
1160 if (increment != null && increment.compareTo(java.math.BigDecimal.ZERO) == 0) {
1161 properties.setMaximumFractionDigits(Integer.MAX_VALUE);
1162 return;
1163 }
1164
1165 properties.setRoundingIncrement(increment);
1166 refreshFormatter();
1167 }
1168
1169 /**
1170 * <strong>[icu]</strong> <strong>Rounding and Digit Limits:</strong> Overload of {@link
1171 * #setRoundingIncrement(java.math.BigDecimal)}.
1172 *
1173 * @param increment The increment to which numbers are to be rounded.
1174 * @see #setRoundingIncrement
1175 */
setRoundingIncrement(BigDecimal increment)1176 public synchronized void setRoundingIncrement(BigDecimal increment) {
1177 java.math.BigDecimal javaBigDecimal = (increment == null) ? null : increment.toBigDecimal();
1178 setRoundingIncrement(javaBigDecimal);
1179 }
1180
1181 /**
1182 * <strong>[icu]</strong> <strong>Rounding and Digit Limits:</strong> Overload of {@link
1183 * #setRoundingIncrement(java.math.BigDecimal)}.
1184 *
1185 * @param increment The increment to which numbers are to be rounded.
1186 * @see #setRoundingIncrement
1187 */
setRoundingIncrement(double increment)1188 public synchronized void setRoundingIncrement(double increment) {
1189 if (increment == 0) {
1190 setRoundingIncrement((java.math.BigDecimal) null);
1191 } else {
1192 java.math.BigDecimal javaBigDecimal = java.math.BigDecimal.valueOf(increment);
1193 setRoundingIncrement(javaBigDecimal);
1194 }
1195 }
1196
1197 /**
1198 * Returns the rounding mode being used to round numbers.
1199 *
1200 * @see #setRoundingMode
1201 */
1202 @Override
getRoundingMode()1203 public synchronized int getRoundingMode() {
1204 RoundingMode mode = exportedProperties.getRoundingMode();
1205 return (mode == null) ? 0 : mode.ordinal();
1206 }
1207
1208 /**
1209 * <strong>Rounding and Digit Limits:</strong> Sets the {@link RoundingMode} used to round
1210 * numbers. The default rounding mode is HALF_EVEN, which rounds decimals to their closest whole
1211 * number, and rounds to the closest even number if at the midpoint.
1212 *
1213 * <p>For more detail on rounding modes, see <a
1214 * href="http://userguide.icu-project.org/formatparse/numbers/rounding-modes">the ICU User
1215 * Guide</a>.
1216 *
1217 * <p>For backwards compatibility, the rounding mode is specified as an int argument, which can be
1218 * from either the constants in {@link BigDecimal} or the ordinal value of {@link RoundingMode}.
1219 * The following two calls are functionally equivalent.
1220 *
1221 * <pre>
1222 * df.setRoundingMode(BigDecimal.ROUND_CEILING);
1223 * df.setRoundingMode(RoundingMode.CEILING.ordinal());
1224 * </pre>
1225 *
1226 * @param roundingMode The integer constant rounding mode to use when formatting numbers.
1227 */
1228 @Override
setRoundingMode(int roundingMode)1229 public synchronized void setRoundingMode(int roundingMode) {
1230 properties.setRoundingMode(RoundingMode.valueOf(roundingMode));
1231 refreshFormatter();
1232 }
1233
1234 /**
1235 * <strong>[icu]</strong> Returns the {@link java.math.MathContext} being used to round numbers.
1236 *
1237 * @see #setMathContext
1238 */
getMathContext()1239 public synchronized java.math.MathContext getMathContext() {
1240 java.math.MathContext mathContext = exportedProperties.getMathContext();
1241 assert mathContext != null;
1242 return mathContext;
1243 }
1244
1245 /**
1246 * <strong>[icu]</strong> <strong>Rounding and Digit Limits:</strong> Sets the {@link java.math.MathContext} used
1247 * to round numbers. A "math context" encodes both a rounding mode and a number of significant
1248 * digits. Most users should call {@link #setRoundingMode} and/or {@link
1249 * #setMaximumSignificantDigits} instead of this method.
1250 *
1251 * <p>When formatting, since no division is ever performed, the default MathContext is unlimited
1252 * significant digits. However, when division occurs during parsing to correct for percentages and
1253 * multipliers, a MathContext of 34 digits, the IEEE 754R Decimal128 standard, is used by default.
1254 * If you require more than 34 digits when parsing, you can set a custom MathContext using this
1255 * method.
1256 *
1257 * @param mathContext The MathContext to use when rounding numbers.
1258 * @throws ArithmeticException when inverting multiplier produces a non-terminating decimal result
1259 * in conjunction with MathContext of unlimited precision.
1260 * @see java.math.MathContext
1261 */
setMathContext(java.math.MathContext mathContext)1262 public synchronized void setMathContext(java.math.MathContext mathContext) {
1263 properties.setMathContext(mathContext);
1264 refreshFormatter();
1265 }
1266
1267 // Remember the ICU math context form in order to be able to return it from the API.
1268 // NOTE: This value is not serialized. (should it be?)
1269 private transient int icuMathContextForm = MathContext.PLAIN;
1270
1271 /**
1272 * <strong>[icu]</strong> Returns the {@link ohos.global.icu.math.MathContext} being used to round numbers.
1273 *
1274 * @see #setMathContext
1275 */
getMathContextICU()1276 public synchronized MathContext getMathContextICU() {
1277 java.math.MathContext mathContext = getMathContext();
1278 return new MathContext(
1279 mathContext.getPrecision(),
1280 icuMathContextForm,
1281 false,
1282 mathContext.getRoundingMode().ordinal());
1283 }
1284
1285 /**
1286 * <strong>[icu]</strong> <strong>Rounding and Digit Limits:</strong> Overload of {@link #setMathContext} for
1287 * {@link ohos.global.icu.math.MathContext}.
1288 *
1289 * @param mathContextICU The MathContext to use when rounding numbers.
1290 * @throws ArithmeticException when inverting multiplier produces a non-terminating decimal result
1291 * in conjunction with MathContext of unlimited precision.
1292 * @see #setMathContext(java.math.MathContext)
1293 */
setMathContextICU(MathContext mathContextICU)1294 public synchronized void setMathContextICU(MathContext mathContextICU) {
1295 icuMathContextForm = mathContextICU.getForm();
1296 java.math.MathContext mathContext;
1297 if (mathContextICU.getLostDigits()) {
1298 // The getLostDigits() feature in ICU MathContext means "throw an ArithmeticException if
1299 // rounding causes digits to be lost". That feature is called RoundingMode.UNNECESSARY in
1300 // Java MathContext.
1301 mathContext = new java.math.MathContext(mathContextICU.getDigits(), RoundingMode.UNNECESSARY);
1302 } else {
1303 mathContext =
1304 new java.math.MathContext(
1305 mathContextICU.getDigits(), RoundingMode.valueOf(mathContextICU.getRoundingMode()));
1306 }
1307 setMathContext(mathContext);
1308 }
1309
1310 /**
1311 * Returns the effective minimum number of digits before the decimal separator.
1312 *
1313 * @see #setMinimumIntegerDigits
1314 */
1315 @Override
getMinimumIntegerDigits()1316 public synchronized int getMinimumIntegerDigits() {
1317 return exportedProperties.getMinimumIntegerDigits();
1318 }
1319
1320 /**
1321 * <strong>Rounding and Digit Limits:</strong> Sets the minimum number of digits to display before
1322 * the decimal separator. If the number has fewer than this many digits, the number is padded with
1323 * zeros.
1324 *
1325 * <p>For example, if minimum integer digits is 3, the number 12.3 will be printed as "001.23".
1326 *
1327 * <p>Minimum integer and minimum and maximum fraction digits can be specified via the pattern
1328 * string. For example, "#,#00.00#" has 2 minimum integer digits, 2 minimum fraction digits, and 3
1329 * maximum fraction digits. Note that it is not possible to specify maximium integer digits in the
1330 * pattern except in scientific notation.
1331 *
1332 * <p>If minimum and maximum integer, fraction, or significant digits conflict with each other,
1333 * the most recently specified value is used. For example, if there is a formatter with minInt=5,
1334 * and then you set maxInt=3, then minInt will be changed to 3.
1335 *
1336 * @param value The minimum number of digits before the decimal separator.
1337 */
1338 @Override
setMinimumIntegerDigits(int value)1339 public synchronized void setMinimumIntegerDigits(int value) {
1340 // For backwards compatibility, conflicting min/max need to keep the most recent setting.
1341 int max = properties.getMaximumIntegerDigits();
1342 if (max >= 0 && max < value) {
1343 properties.setMaximumIntegerDigits(value);
1344 }
1345 properties.setMinimumIntegerDigits(value);
1346 refreshFormatter();
1347 }
1348
1349 /**
1350 * Returns the effective maximum number of digits before the decimal separator.
1351 *
1352 * @see #setMaximumIntegerDigits
1353 */
1354 @Override
getMaximumIntegerDigits()1355 public synchronized int getMaximumIntegerDigits() {
1356 return exportedProperties.getMaximumIntegerDigits();
1357 }
1358
1359 /**
1360 * <strong>Rounding and Digit Limits:</strong> Sets the maximum number of digits to display before
1361 * the decimal separator. If the number has more than this many digits, the number is truncated.
1362 *
1363 * <p>For example, if maximum integer digits is 3, the number 12345 will be printed as "345".
1364 *
1365 * <p>Minimum integer and minimum and maximum fraction digits can be specified via the pattern
1366 * string. For example, "#,#00.00#" has 2 minimum integer digits, 2 minimum fraction digits, and 3
1367 * maximum fraction digits. Note that it is not possible to specify maximium integer digits in the
1368 * pattern except in scientific notation.
1369 *
1370 * <p>If minimum and maximum integer, fraction, or significant digits conflict with each other,
1371 * the most recently specified value is used. For example, if there is a formatter with minInt=5,
1372 * and then you set maxInt=3, then minInt will be changed to 3.
1373 *
1374 * @param value The maximum number of digits before the decimal separator.
1375 */
1376 @Override
setMaximumIntegerDigits(int value)1377 public synchronized void setMaximumIntegerDigits(int value) {
1378 int min = properties.getMinimumIntegerDigits();
1379 if (min >= 0 && min > value) {
1380 properties.setMinimumIntegerDigits(value);
1381 }
1382 properties.setMaximumIntegerDigits(value);
1383 refreshFormatter();
1384 }
1385
1386 /**
1387 * Returns the effective minimum number of integer digits after the decimal separator.
1388 *
1389 * @see #setMaximumIntegerDigits
1390 */
1391 @Override
getMinimumFractionDigits()1392 public synchronized int getMinimumFractionDigits() {
1393 return exportedProperties.getMinimumFractionDigits();
1394 }
1395
1396 /**
1397 * <strong>Rounding and Digit Limits:</strong> Sets the minimum number of digits to display after
1398 * the decimal separator. If the number has fewer than this many digits, the number is padded with
1399 * zeros.
1400 *
1401 * <p>For example, if minimum fraction digits is 2, the number 123.4 will be printed as "123.40".
1402 *
1403 * <p>Minimum integer and minimum and maximum fraction digits can be specified via the pattern
1404 * string. For example, "#,#00.00#" has 2 minimum integer digits, 2 minimum fraction digits, and 3
1405 * maximum fraction digits. Note that it is not possible to specify maximium integer digits in the
1406 * pattern except in scientific notation.
1407 *
1408 * <p>If minimum and maximum integer, fraction, or significant digits conflict with each other,
1409 * the most recently specified value is used. For example, if there is a formatter with minInt=5,
1410 * and then you set maxInt=3, then minInt will be changed to 3.
1411 *
1412 * <p>See {@link #setRoundingIncrement} and {@link #setMaximumSignificantDigits} for two other
1413 * ways of specifying rounding strategies.
1414 *
1415 * @param value The minimum number of integer digits after the decimal separator.
1416 * @see #setRoundingMode
1417 * @see #setRoundingIncrement
1418 * @see #setMaximumSignificantDigits
1419 */
1420 @Override
setMinimumFractionDigits(int value)1421 public synchronized void setMinimumFractionDigits(int value) {
1422 int max = properties.getMaximumFractionDigits();
1423 if (max >= 0 && max < value) {
1424 properties.setMaximumFractionDigits(value);
1425 }
1426 properties.setMinimumFractionDigits(value);
1427 refreshFormatter();
1428 }
1429
1430 /**
1431 * Returns the effective maximum number of integer digits after the decimal separator.
1432 *
1433 * @see #setMaximumIntegerDigits
1434 */
1435 @Override
getMaximumFractionDigits()1436 public synchronized int getMaximumFractionDigits() {
1437 return exportedProperties.getMaximumFractionDigits();
1438 }
1439
1440 /**
1441 * <strong>Rounding and Digit Limits:</strong> Sets the maximum number of digits to display after
1442 * the decimal separator. If the number has more than this many digits, the number is rounded
1443 * according to the rounding mode.
1444 *
1445 * <p>For example, if maximum fraction digits is 2, the number 123.456 will be printed as
1446 * "123.46".
1447 *
1448 * <p>Minimum integer and minimum and maximum fraction digits can be specified via the pattern
1449 * string. For example, "#,#00.00#" has 2 minimum integer digits, 2 minimum fraction digits, and 3
1450 * maximum fraction digits. Note that it is not possible to specify maximium integer digits in the
1451 * pattern except in scientific notation.
1452 *
1453 * <p>If minimum and maximum integer, fraction, or significant digits conflict with each other,
1454 * the most recently specified value is used. For example, if there is a formatter with minInt=5,
1455 * and then you set maxInt=3, then minInt will be changed to 3.
1456 *
1457 * @param value The maximum number of integer digits after the decimal separator.
1458 * @see #setRoundingMode
1459 */
1460 @Override
setMaximumFractionDigits(int value)1461 public synchronized void setMaximumFractionDigits(int value) {
1462 int min = properties.getMinimumFractionDigits();
1463 if (min >= 0 && min > value) {
1464 properties.setMinimumFractionDigits(value);
1465 }
1466 properties.setMaximumFractionDigits(value);
1467 refreshFormatter();
1468 }
1469
1470 /**
1471 * <strong>[icu]</strong> Returns whether significant digits are being used in rounding.
1472 *
1473 * @see #setSignificantDigitsUsed
1474 */
areSignificantDigitsUsed()1475 public synchronized boolean areSignificantDigitsUsed() {
1476 return properties.getMinimumSignificantDigits() != -1
1477 || properties.getMaximumSignificantDigits() != -1;
1478 }
1479
1480 /**
1481 * <strong>[icu]</strong> <strong>Rounding and Digit Limits:</strong> Sets whether significant digits are to be
1482 * used in rounding.
1483 *
1484 * <p>Calling <code>df.setSignificantDigitsUsed(true)</code> is functionally equivalent to:
1485 *
1486 * <pre>
1487 * df.setMinimumSignificantDigits(1);
1488 * df.setMaximumSignificantDigits(6);
1489 * </pre>
1490 *
1491 * @param useSignificantDigits true to enable significant digit rounding; false to disable it.
1492 */
setSignificantDigitsUsed(boolean useSignificantDigits)1493 public synchronized void setSignificantDigitsUsed(boolean useSignificantDigits) {
1494 int oldMinSig = properties.getMinimumSignificantDigits();
1495 int oldMaxSig = properties.getMaximumSignificantDigits();
1496 // These are the default values from the old implementation.
1497 if (useSignificantDigits) {
1498 if (oldMinSig != -1 || oldMaxSig != -1) {
1499 return;
1500 }
1501 } else {
1502 if (oldMinSig == -1 && oldMaxSig == -1) {
1503 return;
1504 }
1505 }
1506 int minSig = useSignificantDigits ? 1 : -1;
1507 int maxSig = useSignificantDigits ? 6 : -1;
1508 properties.setMinimumSignificantDigits(minSig);
1509 properties.setMaximumSignificantDigits(maxSig);
1510 refreshFormatter();
1511 }
1512
1513 /**
1514 * <strong>[icu]</strong> Returns the effective minimum number of significant digits displayed.
1515 *
1516 * @see #setMinimumSignificantDigits
1517 */
getMinimumSignificantDigits()1518 public synchronized int getMinimumSignificantDigits() {
1519 return exportedProperties.getMinimumSignificantDigits();
1520 }
1521
1522 /**
1523 * <strong>[icu]</strong> <strong>Rounding and Digit Limits:</strong> Sets the minimum number of significant
1524 * digits to be displayed. If the number of significant digits is less than this value, the number
1525 * will be padded with zeros as necessary.
1526 *
1527 * <p>For example, if minimum significant digits is 3 and the number is 1.2, the number will be
1528 * printed as "1.20".
1529 *
1530 * <p>If minimum and maximum integer, fraction, or significant digits conflict with each other,
1531 * the most recently specified value is used. For example, if there is a formatter with minInt=5,
1532 * and then you set maxInt=3, then minInt will be changed to 3.
1533 *
1534 * @param value The minimum number of significant digits to display.
1535 */
setMinimumSignificantDigits(int value)1536 public synchronized void setMinimumSignificantDigits(int value) {
1537 int max = properties.getMaximumSignificantDigits();
1538 if (max >= 0 && max < value) {
1539 properties.setMaximumSignificantDigits(value);
1540 }
1541 properties.setMinimumSignificantDigits(value);
1542 refreshFormatter();
1543 }
1544
1545 /**
1546 * <strong>[icu]</strong> Returns the effective maximum number of significant digits displayed.
1547 *
1548 * @see #setMaximumSignificantDigits
1549 */
getMaximumSignificantDigits()1550 public synchronized int getMaximumSignificantDigits() {
1551 return exportedProperties.getMaximumSignificantDigits();
1552 }
1553
1554 /**
1555 * <strong>[icu]</strong> <strong>Rounding and Digit Limits:</strong> Sets the maximum number of significant
1556 * digits to be displayed. If the number of significant digits in the number exceeds this value,
1557 * the number will be rounded according to the current rounding mode.
1558 *
1559 * <p>For example, if maximum significant digits is 3 and the number is 12345, the number will be
1560 * printed as "12300".
1561 *
1562 * <p>If minimum and maximum integer, fraction, or significant digits conflict with each other,
1563 * the most recently specified value is used. For example, if there is a formatter with minInt=5,
1564 * and then you set maxInt=3, then minInt will be changed to 3.
1565 *
1566 * <p>See {@link #setRoundingIncrement} and {@link #setMaximumFractionDigits} for two other ways
1567 * of specifying rounding strategies.
1568 *
1569 * @param value The maximum number of significant digits to display.
1570 * @see #setRoundingMode
1571 * @see #setRoundingIncrement
1572 * @see #setMaximumFractionDigits
1573 */
setMaximumSignificantDigits(int value)1574 public synchronized void setMaximumSignificantDigits(int value) {
1575 int min = properties.getMinimumSignificantDigits();
1576 if (min >= 0 && min > value) {
1577 properties.setMinimumSignificantDigits(value);
1578 }
1579 properties.setMaximumSignificantDigits(value);
1580 refreshFormatter();
1581 }
1582
1583 /**
1584 * Returns the minimum number of characters in formatted output.
1585 *
1586 * @see #setFormatWidth
1587 */
getFormatWidth()1588 public synchronized int getFormatWidth() {
1589 return properties.getFormatWidth();
1590 }
1591
1592 /**
1593 * <strong>Padding:</strong> Sets the minimum width of the string output by the formatting
1594 * pipeline. For example, if padding is enabled and paddingWidth is set to 6, formatting the
1595 * number "3.14159" with the pattern "0.00" will result in "··3.14" if '·' is your padding string.
1596 *
1597 * <p>If the number is longer than your padding width, the number will display as if no padding
1598 * width had been specified, which may result in strings longer than the padding width.
1599 *
1600 * <p>Padding can be specified in the pattern string using the '*' symbol. For example, the format
1601 * "*x######0" has a format width of 7 and a pad character of 'x'.
1602 *
1603 * <p>Padding is currently counted in UTF-16 code units; see <a
1604 * href="http://bugs.icu-project.org/trac/ticket/13034">ticket #13034</a> for more information.
1605 *
1606 * @param width The minimum number of characters in the output.
1607 * @see #setPadCharacter
1608 * @see #setPadPosition
1609 */
setFormatWidth(int width)1610 public synchronized void setFormatWidth(int width) {
1611 properties.setFormatWidth(width);
1612 refreshFormatter();
1613 }
1614
1615 /**
1616 * <strong>[icu]</strong> Returns the character used for padding.
1617 *
1618 * @see #setPadCharacter
1619 */
getPadCharacter()1620 public synchronized char getPadCharacter() {
1621 CharSequence paddingString = properties.getPadString();
1622 if (paddingString == null) {
1623 return Padder.FALLBACK_PADDING_STRING.charAt(0);
1624 } else {
1625 return paddingString.charAt(0);
1626 }
1627 }
1628
1629 /**
1630 * <strong>[icu]</strong> <strong>Padding:</strong> Sets the character used to pad numbers that are narrower than
1631 * the width specified in {@link #setFormatWidth}.
1632 *
1633 * <p>In the pattern string, the padding character is the token that follows '*' before or after
1634 * the prefix or suffix.
1635 *
1636 * @param padChar The character used for padding.
1637 * @see #setFormatWidth
1638 */
setPadCharacter(char padChar)1639 public synchronized void setPadCharacter(char padChar) {
1640 properties.setPadString(Character.toString(padChar));
1641 refreshFormatter();
1642 }
1643
1644 /**
1645 * <strong>[icu]</strong> Returns the position used for padding.
1646 *
1647 * @see #setPadPosition
1648 */
getPadPosition()1649 public synchronized int getPadPosition() {
1650 PadPosition loc = properties.getPadPosition();
1651 return (loc == null) ? PAD_BEFORE_PREFIX : loc.toOld();
1652 }
1653
1654 /**
1655 * <strong>[icu]</strong> <strong>Padding:</strong> Sets the position where to insert the pad character when
1656 * narrower than the width specified in {@link #setFormatWidth}. For example, consider the pattern
1657 * "P123S" with padding width 8 and padding char "*". The four positions are:
1658 *
1659 * <ul>
1660 * <li>{@link DecimalFormat#PAD_BEFORE_PREFIX} ⇒ "***P123S"
1661 * <li>{@link DecimalFormat#PAD_AFTER_PREFIX} ⇒ "P***123S"
1662 * <li>{@link DecimalFormat#PAD_BEFORE_SUFFIX} ⇒ "P123***S"
1663 * <li>{@link DecimalFormat#PAD_AFTER_SUFFIX} ⇒ "P123S***"
1664 * </ul>
1665 *
1666 * @param padPos The position used for padding.
1667 * @see #setFormatWidth
1668 */
setPadPosition(int padPos)1669 public synchronized void setPadPosition(int padPos) {
1670 properties.setPadPosition(PadPosition.fromOld(padPos));
1671 refreshFormatter();
1672 }
1673
1674 /**
1675 * <strong>[icu]</strong> Returns whether scientific (exponential) notation is enabled on this formatter.
1676 *
1677 * @see #setScientificNotation
1678 */
isScientificNotation()1679 public synchronized boolean isScientificNotation() {
1680 return properties.getMinimumExponentDigits() != -1;
1681 }
1682
1683 /**
1684 * <strong>[icu]</strong> <strong>Scientific Notation:</strong> Sets whether this formatter should print in
1685 * scientific (exponential) notation. For example, if scientific notation is enabled, the number
1686 * 123000 will be printed as "1.23E5" in locale <em>en-US</em>. A locale-specific symbol is used
1687 * as the exponent separator.
1688 *
1689 * <p>Calling <code>df.setScientificNotation(true)</code> is functionally equivalent to calling
1690 * <code>df.setMinimumExponentDigits(1)</code>.
1691 *
1692 * @param useScientific true to enable scientific notation; false to disable it.
1693 * @see #setMinimumExponentDigits
1694 */
setScientificNotation(boolean useScientific)1695 public synchronized void setScientificNotation(boolean useScientific) {
1696 if (useScientific) {
1697 properties.setMinimumExponentDigits(1);
1698 } else {
1699 properties.setMinimumExponentDigits(-1);
1700 }
1701 refreshFormatter();
1702 }
1703
1704 /**
1705 * <strong>[icu]</strong> Returns the minimum number of digits printed in the exponent in scientific notation.
1706 *
1707 * @see #setMinimumExponentDigits
1708 */
getMinimumExponentDigits()1709 public synchronized byte getMinimumExponentDigits() {
1710 return (byte) properties.getMinimumExponentDigits();
1711 }
1712
1713 /**
1714 * <strong>[icu]</strong> <strong>Scientific Notation:</strong> Sets the minimum number of digits to be printed in
1715 * the exponent. For example, if minimum exponent digits is 3, the number 123000 will be printed
1716 * as "1.23E005".
1717 *
1718 * <p>This setting corresponds to the number of zeros after the 'E' in a pattern string such as
1719 * "0.00E000".
1720 *
1721 * @param minExpDig The minimum number of digits in the exponent.
1722 */
setMinimumExponentDigits(byte minExpDig)1723 public synchronized void setMinimumExponentDigits(byte minExpDig) {
1724 properties.setMinimumExponentDigits(minExpDig);
1725 refreshFormatter();
1726 }
1727
1728 /**
1729 * <strong>[icu]</strong> Returns whether the sign (plus or minus) is always printed in scientific notation.
1730 *
1731 * @see #setExponentSignAlwaysShown
1732 */
isExponentSignAlwaysShown()1733 public synchronized boolean isExponentSignAlwaysShown() {
1734 return properties.getExponentSignAlwaysShown();
1735 }
1736
1737 /**
1738 * <strong>[icu]</strong> <strong>Scientific Notation:</strong> Sets whether the sign (plus or minus) is always to
1739 * be shown in the exponent in scientific notation. For example, if this setting is enabled, the
1740 * number 123000 will be printed as "1.23E+5" in locale <em>en-US</em>. The number 0.0000123 will
1741 * always be printed as "1.23E-5" in locale <em>en-US</em> whether or not this setting is enabled.
1742 *
1743 * <p>This setting corresponds to the '+' in a pattern such as "0.00E+0".
1744 *
1745 * @param expSignAlways true to always shown the sign in the exponent; false to show it for
1746 * negatives but not positives.
1747 */
setExponentSignAlwaysShown(boolean expSignAlways)1748 public synchronized void setExponentSignAlwaysShown(boolean expSignAlways) {
1749 properties.setExponentSignAlwaysShown(expSignAlways);
1750 refreshFormatter();
1751 }
1752
1753 /**
1754 * Returns whether or not grouping separators are being printed in the output.
1755 *
1756 * @see #setGroupingUsed
1757 */
1758 @Override
isGroupingUsed()1759 public synchronized boolean isGroupingUsed() {
1760 return properties.getGroupingUsed();
1761 }
1762
1763 /**
1764 * <strong>Grouping:</strong> Sets whether grouping is to be used when formatting numbers.
1765 * Grouping means whether the thousands, millions, billions, and larger powers of ten should be
1766 * separated by a grouping separator (a comma in <em>en-US</em>).
1767 *
1768 * <p>For example, if grouping is enabled, 12345 will be printed as "12,345" in <em>en-US</em>. If
1769 * grouping were disabled, it would instead be printed as simply "12345".
1770 *
1771 * @param enabled true to enable grouping separators; false to disable them.
1772 * @see #setGroupingSize
1773 * @see #setSecondaryGroupingSize
1774 */
1775 @Override
setGroupingUsed(boolean enabled)1776 public synchronized void setGroupingUsed(boolean enabled) {
1777 properties.setGroupingUsed(enabled);
1778 refreshFormatter();
1779 }
1780
1781 /**
1782 * Returns the primary grouping size in use.
1783 *
1784 * @see #setGroupingSize
1785 */
getGroupingSize()1786 public synchronized int getGroupingSize() {
1787 if (properties.getGroupingSize() < 0) {
1788 return 0;
1789 }
1790 return properties.getGroupingSize();
1791 }
1792
1793 /**
1794 * <strong>Grouping:</strong> Sets the primary grouping size (distance between grouping
1795 * separators) used when formatting large numbers. For most locales, this defaults to 3: the
1796 * number of digits between the ones and thousands place, between thousands and millions, and so
1797 * forth.
1798 *
1799 * <p>For example, with a grouping size of 3, the number 1234567 will be formatted as "1,234,567".
1800 *
1801 * <p>Grouping size can also be specified in the pattern: for example, "#,##0" corresponds to a
1802 * grouping size of 3.
1803 *
1804 * @param width The grouping size to use.
1805 * @see #setSecondaryGroupingSize
1806 */
setGroupingSize(int width)1807 public synchronized void setGroupingSize(int width) {
1808 properties.setGroupingSize(width);
1809 refreshFormatter();
1810 }
1811
1812 /**
1813 * <strong>[icu]</strong> Returns the secondary grouping size in use.
1814 *
1815 * @see #setSecondaryGroupingSize
1816 */
getSecondaryGroupingSize()1817 public synchronized int getSecondaryGroupingSize() {
1818 int grouping2 = properties.getSecondaryGroupingSize();
1819 if (grouping2 < 0) {
1820 return 0;
1821 }
1822 return grouping2;
1823 }
1824
1825 /**
1826 * <strong>[icu]</strong> <strong>Grouping:</strong> Sets the secondary grouping size (distance between grouping
1827 * separators after the first separator) used when formatting large numbers. In many south Asian
1828 * locales, this is set to 2.
1829 *
1830 * <p>For example, with primary grouping size 3 and secondary grouping size 2, the number 1234567
1831 * will be formatted as "12,34,567".
1832 *
1833 * <p>Grouping size can also be specified in the pattern: for example, "#,##,##0" corresponds to a
1834 * primary grouping size of 3 and a secondary grouping size of 2.
1835 *
1836 * @param width The secondary grouping size to use.
1837 * @see #setGroupingSize
1838 */
setSecondaryGroupingSize(int width)1839 public synchronized void setSecondaryGroupingSize(int width) {
1840 properties.setSecondaryGroupingSize(width);
1841 refreshFormatter();
1842 }
1843
1844 /**
1845 * <strong>[icu]</strong> Returns the minimum number of digits before grouping is triggered.
1846 *
1847 * @see #setMinimumGroupingDigits
1848 */
getMinimumGroupingDigits()1849 public synchronized int getMinimumGroupingDigits() {
1850 if (properties.getMinimumGroupingDigits() > 0) {
1851 return properties.getMinimumGroupingDigits();
1852 }
1853 return 1;
1854 }
1855
1856 /**
1857 * <strong>[icu]</strong> Sets the minimum number of digits that must be before the first grouping separator in
1858 * order for the grouping separator to be printed. For example, if minimum grouping digits is set
1859 * to 2, in <em>en-US</em>, 1234 will be printed as "1234" and 12345 will be printed as "12,345".
1860 *
1861 * @param number The minimum number of digits before grouping is triggered.
1862 */
setMinimumGroupingDigits(int number)1863 public synchronized void setMinimumGroupingDigits(int number) {
1864 properties.setMinimumGroupingDigits(number);
1865 refreshFormatter();
1866 }
1867
1868 /**
1869 * Returns whether the decimal separator is shown on integers.
1870 *
1871 * @see #setDecimalSeparatorAlwaysShown
1872 */
isDecimalSeparatorAlwaysShown()1873 public synchronized boolean isDecimalSeparatorAlwaysShown() {
1874 return properties.getDecimalSeparatorAlwaysShown();
1875 }
1876
1877 /**
1878 * <strong>Separators:</strong> Sets whether the decimal separator (a period in <em>en-US</em>) is
1879 * shown on integers. For example, if this setting is turned on, formatting 123 will result in
1880 * "123." with the decimal separator.
1881 *
1882 * <p>This setting can be specified in the pattern for integer formats: "#,##0." is an example.
1883 *
1884 * @param value true to always show the decimal separator; false to show it only when there is a
1885 * fraction part of the number.
1886 */
setDecimalSeparatorAlwaysShown(boolean value)1887 public synchronized void setDecimalSeparatorAlwaysShown(boolean value) {
1888 properties.setDecimalSeparatorAlwaysShown(value);
1889 refreshFormatter();
1890 }
1891
1892 /**
1893 * Returns the currency used to display currency amounts. May be null.
1894 *
1895 * @see #setCurrency
1896 * @see DecimalFormatSymbols#getCurrency
1897 */
1898 @Override
getCurrency()1899 public synchronized Currency getCurrency() {
1900 return exportedProperties.getCurrency();
1901 }
1902
1903 /**
1904 * Sets the currency to be used when formatting numbers. The effect is twofold:
1905 *
1906 * <ol>
1907 * <li>Substitutions for currency symbols in the pattern string will use this currency
1908 * <li>The rounding mode will obey the rules for this currency (see {@link #setCurrencyUsage})
1909 * </ol>
1910 *
1911 * <strong>Important:</strong> Displaying the currency in the output requires that the patter
1912 * associated with this formatter contains a currency symbol '¤'. This will be the case if the
1913 * instance was created via {@link #getCurrencyInstance} or one of its friends.
1914 *
1915 * @param currency The currency to use.
1916 */
1917 @Override
setCurrency(Currency currency)1918 public synchronized void setCurrency(Currency currency) {
1919 properties.setCurrency(currency);
1920 if (currency != null) {
1921 symbols.setCurrency(currency);
1922 }
1923 refreshFormatter();
1924 }
1925
1926 /**
1927 * <strong>[icu]</strong> Returns the strategy for rounding currency amounts.
1928 *
1929 * @see #setCurrencyUsage
1930 */
getCurrencyUsage()1931 public synchronized CurrencyUsage getCurrencyUsage() {
1932 // CurrencyUsage is not exported, so we have to get it from the input property bag.
1933 // TODO: Should we export CurrencyUsage instead?
1934 CurrencyUsage usage = properties.getCurrencyUsage();
1935 if (usage == null) {
1936 usage = CurrencyUsage.STANDARD;
1937 }
1938 return usage;
1939 }
1940
1941 /**
1942 * <strong>[icu]</strong> Sets the currency-dependent strategy to use when rounding numbers. There are two
1943 * strategies:
1944 *
1945 * <ul>
1946 * <li>STANDARD: When the amount displayed is intended for banking statements or electronic
1947 * transfer.
1948 * <li>CASH: When the amount displayed is intended to be representable in physical currency,
1949 * like at a cash register.
1950 * </ul>
1951 *
1952 * CASH mode is relevant in currencies that do not have tender down to the penny. For more
1953 * information on the two rounding strategies, see <a
1954 * href="http://unicode.org/reports/tr35/tr35-numbers.html#Supplemental_Currency_Data">UTS
1955 * #35</a>. If omitted, the strategy defaults to STANDARD. To override currency rounding
1956 * altogether, use {@link #setMinimumFractionDigits} and {@link #setMaximumFractionDigits} or
1957 * {@link #setRoundingIncrement}.
1958 *
1959 * @param usage The strategy to use when rounding in the current currency.
1960 */
setCurrencyUsage(CurrencyUsage usage)1961 public synchronized void setCurrencyUsage(CurrencyUsage usage) {
1962 properties.setCurrencyUsage(usage);
1963 refreshFormatter();
1964 }
1965
1966 /**
1967 * <strong>[icu]</strong> Returns the current instance of CurrencyPluralInfo.
1968 *
1969 * @see #setCurrencyPluralInfo
1970 */
getCurrencyPluralInfo()1971 public synchronized CurrencyPluralInfo getCurrencyPluralInfo() {
1972 // CurrencyPluralInfo also is not exported.
1973 return properties.getCurrencyPluralInfo();
1974 }
1975
1976 /**
1977 * <strong>[icu]</strong> Sets a custom instance of CurrencyPluralInfo. CurrencyPluralInfo generates pattern
1978 * strings for printing currency long names.
1979 *
1980 * <p><strong>Most users should not call this method directly.</strong> You should instead create
1981 * your formatter via <code>NumberFormat.getInstance(NumberFormat.PLURALCURRENCYSTYLE)</code>.
1982 *
1983 * @param newInfo The CurrencyPluralInfo to use when printing currency long names.
1984 */
setCurrencyPluralInfo(CurrencyPluralInfo newInfo)1985 public synchronized void setCurrencyPluralInfo(CurrencyPluralInfo newInfo) {
1986 properties.setCurrencyPluralInfo(newInfo);
1987 refreshFormatter();
1988 }
1989
1990 /**
1991 * Returns whether {@link #parse} will always return a BigDecimal.
1992 *
1993 * @see #setParseBigDecimal
1994 */
isParseBigDecimal()1995 public synchronized boolean isParseBigDecimal() {
1996 return properties.getParseToBigDecimal();
1997 }
1998
1999 /**
2000 * Whether to make {@link #parse} prefer returning a {@link ohos.global.icu.math.BigDecimal} when
2001 * possible. For strings corresponding to return values of Infinity, -Infinity, NaN, and -0.0, a
2002 * Double will be returned even if ParseBigDecimal is enabled.
2003 *
2004 * @param value true to cause {@link #parse} to prefer BigDecimal; false to let {@link #parse}
2005 * return additional data types like Long or BigInteger.
2006 */
setParseBigDecimal(boolean value)2007 public synchronized void setParseBigDecimal(boolean value) {
2008 properties.setParseToBigDecimal(value);
2009 refreshFormatter();
2010 }
2011
2012 /**
2013 * Always returns 1000, the default prior to ICU 59.
2014 *
2015 * @deprecated Setting max parse digits has no effect since ICU4J 59.
2016 */
2017 @Deprecated
getParseMaxDigits()2018 public int getParseMaxDigits() {
2019 return 1000;
2020 }
2021
2022 /**
2023 * @param maxDigits Prior to ICU 59, the maximum number of digits in the output number after
2024 * exponential notation is applied.
2025 * @deprecated Setting max parse digits has no effect since ICU4J 59.
2026 */
2027 @Deprecated
setParseMaxDigits(int maxDigits)2028 public void setParseMaxDigits(int maxDigits) {}
2029
2030 /**
2031 * {@inheritDoc}
2032 */
2033 @Override
isParseStrict()2034 public synchronized boolean isParseStrict() {
2035 return properties.getParseMode() == ParseMode.STRICT;
2036 }
2037
2038 /**
2039 * {@inheritDoc}
2040 */
2041 @Override
setParseStrict(boolean parseStrict)2042 public synchronized void setParseStrict(boolean parseStrict) {
2043 ParseMode mode = parseStrict ? ParseMode.STRICT : ParseMode.LENIENT;
2044 properties.setParseMode(mode);
2045 refreshFormatter();
2046 }
2047
2048 /**
2049 * Android libcore uses this internal method to set {@link ParseMode#JAVA_COMPATIBILITY}.
2050 * @deprecated This API is ICU internal only.
2051 * @hide draft / provisional / internal are hidden on OHOS
2052 */
2053 @Deprecated
setParseStrictMode(ParseMode parseMode)2054 public synchronized void setParseStrictMode(ParseMode parseMode) {
2055 properties.setParseMode(parseMode);
2056 refreshFormatter();
2057 }
2058
2059 /**
2060 * {@inheritDoc}
2061 *
2062 * @see #setParseIntegerOnly
2063 */
2064 @Override
isParseIntegerOnly()2065 public synchronized boolean isParseIntegerOnly() {
2066 return properties.getParseIntegerOnly();
2067 }
2068
2069 /**
2070 * <strong>Parsing:</strong> {@inheritDoc}
2071 *
2072 * <p>This is functionally equivalent to calling {@link #setDecimalPatternMatchRequired} and a
2073 * pattern without a decimal point.
2074 *
2075 * @param parseIntegerOnly true to ignore fractional parts of numbers when parsing; false to
2076 * consume fractional parts.
2077 */
2078 @Override
setParseIntegerOnly(boolean parseIntegerOnly)2079 public synchronized void setParseIntegerOnly(boolean parseIntegerOnly) {
2080 properties.setParseIntegerOnly(parseIntegerOnly);
2081 refreshFormatter();
2082 }
2083
2084 /**
2085 * <strong>[icu]</strong> Returns whether the presence of a decimal point must match the pattern.
2086 *
2087 * @see #setDecimalPatternMatchRequired
2088 */
isDecimalPatternMatchRequired()2089 public synchronized boolean isDecimalPatternMatchRequired() {
2090 return properties.getDecimalPatternMatchRequired();
2091 }
2092
2093 /**
2094 * <strong>[icu]</strong> <strong>Parsing:</strong> This method is used to either <em>require</em> or
2095 * <em>forbid</em> the presence of a decimal point in the string being parsed (disabled by
2096 * default). This feature was designed to be an extra layer of strictness on top of strict
2097 * parsing, although it can be used in either lenient mode or strict mode.
2098 *
2099 * <p>To <em>require</em> a decimal point, call this method in combination with either a pattern
2100 * containing a decimal point or with {@link #setDecimalSeparatorAlwaysShown}.
2101 *
2102 * <pre>
2103 * // Require a decimal point in the string being parsed:
2104 * df.applyPattern("#.");
2105 * df.setDecimalPatternMatchRequired(true);
2106 *
2107 * // Alternatively:
2108 * df.setDecimalSeparatorAlwaysShown(true);
2109 * df.setDecimalPatternMatchRequired(true);
2110 * </pre>
2111 *
2112 * To <em>forbid</em> a decimal point, call this method in combination with a pattern containing
2113 * no decimal point. Alternatively, use {@link #setParseIntegerOnly} for the same behavior without
2114 * depending on the contents of the pattern string.
2115 *
2116 * <pre>
2117 * // Forbid a decimal point in the string being parsed:
2118 * df.applyPattern("#");
2119 * df.setDecimalPatternMatchRequired(true);
2120 * </pre>
2121 *
2122 * @param value true to either require or forbid the decimal point according to the pattern; false
2123 * to disable this feature.
2124 * @see #setParseIntegerOnly
2125 */
setDecimalPatternMatchRequired(boolean value)2126 public synchronized void setDecimalPatternMatchRequired(boolean value) {
2127 properties.setDecimalPatternMatchRequired(value);
2128 refreshFormatter();
2129 }
2130
2131 /**
2132 * <strong>[icu]</strong> Returns whether to ignore exponents when parsing.
2133 *
2134 * @see #setParseNoExponent
2135 */
isParseNoExponent()2136 public synchronized boolean isParseNoExponent() {
2137 return properties.getParseNoExponent();
2138 }
2139
2140 /**
2141 * <strong>[icu]</strong> Specifies whether to stop parsing when an exponent separator is encountered. For
2142 * example, parses "123E4" to 123 (with parse position 3) instead of 1230000 (with parse position
2143 * 5).
2144 *
2145 * @param value true to prevent exponents from being parsed; false to allow them to be parsed.
2146 */
setParseNoExponent(boolean value)2147 public synchronized void setParseNoExponent(boolean value) {
2148 properties.setParseNoExponent(value);
2149 refreshFormatter();
2150 }
2151
2152 /**
2153 * <strong>[icu]</strong> Returns whether to force case (uppercase/lowercase) to match when parsing.
2154 *
2155 * @see #setParseNoExponent
2156 */
isParseCaseSensitive()2157 public synchronized boolean isParseCaseSensitive() {
2158 return properties.getParseCaseSensitive();
2159 }
2160
2161 /**
2162 * <strong>[icu]</strong> Specifies whether parsing should require cases to match in affixes, exponent separators,
2163 * and currency codes. Case mapping is performed for each code point using {@link
2164 * UCharacter#foldCase}.
2165 *
2166 * @param value true to force case (uppercase/lowercase) to match when parsing; false to ignore
2167 * case and perform case folding.
2168 */
setParseCaseSensitive(boolean value)2169 public synchronized void setParseCaseSensitive(boolean value) {
2170 properties.setParseCaseSensitive(value);
2171 refreshFormatter();
2172 }
2173
2174 // TODO(sffc): Uncomment for ICU 60 API proposal.
2175 //
2176 // /**
2177 // * {@icu} Returns the strategy used for choosing between grouping and decimal separators when
2178 // * parsing.
2179 // *
2180 // * @see #setParseGroupingMode
2181 // * @category Parsing
2182 // */
2183 // public synchronized GroupingMode getParseGroupingMode() {
2184 // return properties.getParseGroupingMode();
2185 // }
2186 //
2187 // /**
2188 // * {@icu} Sets the strategy used during parsing when a code point needs to be interpreted as
2189 // * either a decimal separator or a grouping separator.
2190 // *
2191 // * <p>The comma, period, space, and apostrophe have different meanings in different locales. For
2192 // * example, in <em>en-US</em> and most American locales, the period is used as a decimal
2193 // * separator, but in <em>es-PY</em> and most European locales, it is used as a grouping separator.
2194 // *
2195 // * Suppose you are in <em>fr-FR</em> the parser encounters the string "1.234". In <em>fr-FR</em>,
2196 // * the grouping is a space and the decimal is a comma. The <em>grouping mode</em> is a mechanism
2197 // * to let you specify whether to accept the string as 1234 (GroupingMode.DEFAULT) or whether to reject it since the separators
2198 // * don't match (GroupingMode.RESTRICTED).
2199 // *
2200 // * When resolving grouping separators, it is the <em>equivalence class</em> of separators that is considered.
2201 // * For example, a period is seen as equal to a fixed set of other period-like characters.
2202 // *
2203 // * @param groupingMode The strategy to use; either DEFAULT or RESTRICTED.
2204 // * @category Parsing
2205 // */
2206 // public synchronized void setParseGroupingMode(GroupingMode groupingMode) {
2207 // properties.setParseGroupingMode(groupingMode);
2208 // refreshFormatter();
2209 // }
2210
2211 //=====================================================================================//
2212 // UTILITIES //
2213 //=====================================================================================//
2214
2215 /**
2216 * Tests for equality between this formatter and another formatter.
2217 *
2218 * <p>If two DecimalFormat instances are equal, then they will always produce the same output.
2219 * However, the reverse is not necessarily true: if two DecimalFormat instances always produce the
2220 * same output, they are not necessarily equal.
2221 */
2222 @Override
equals(Object obj)2223 public synchronized boolean equals(Object obj) {
2224 if (obj == null) return false;
2225 if (obj == this) return true;
2226 if (!(obj instanceof DecimalFormat)) return false;
2227 DecimalFormat other = (DecimalFormat) obj;
2228 return properties.equals(other.properties) && symbols.equals(other.symbols);
2229 }
2230
2231 /**
2232 * {@inheritDoc}
2233 */
2234 @Override
hashCode()2235 public synchronized int hashCode() {
2236 return properties.hashCode() ^ symbols.hashCode();
2237 }
2238
2239 /**
2240 * Returns the default value of toString() with extra DecimalFormat-specific information appended
2241 * to the end of the string. This extra information is intended for debugging purposes, and the
2242 * format is not guaranteed to be stable.
2243 */
2244 @Override
toString()2245 public String toString() {
2246 StringBuilder result = new StringBuilder();
2247 result.append(getClass().getName());
2248 result.append("@");
2249 result.append(Integer.toHexString(hashCode()));
2250 result.append(" { symbols@");
2251 result.append(Integer.toHexString(symbols.hashCode()));
2252 synchronized (this) {
2253 properties.toStringBare(result);
2254 }
2255 result.append(" }");
2256 return result.toString();
2257 }
2258
2259 /**
2260 * Serializes this formatter object to a decimal format pattern string. The result of this method
2261 * is guaranteed to be <em>functionally</em> equivalent to the pattern string used to create this
2262 * instance after incorporating values from the setter methods.
2263 *
2264 * <p>For more information on decimal format pattern strings, see <a
2265 * href="http://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns">UTS #35</a>.
2266 *
2267 * <p><strong>Important:</strong> Not all properties are capable of being encoded in a pattern
2268 * string. See a list of properties in {@link #applyPattern}.
2269 *
2270 * @return A decimal format pattern string.
2271 */
toPattern()2272 public synchronized String toPattern() {
2273 // Pull some properties from exportedProperties and others from properties
2274 // to keep affix patterns intact. In particular, pull rounding properties
2275 // so that CurrencyUsage is reflected properly.
2276 // TODO: Consider putting this logic in PatternString.java instead.
2277 DecimalFormatProperties tprops = new DecimalFormatProperties().copyFrom(properties);
2278 boolean useCurrency = ((tprops.getCurrency() != null)
2279 || tprops.getCurrencyPluralInfo() != null
2280 || tprops.getCurrencyUsage() != null
2281 || AffixUtils.hasCurrencySymbols(tprops.getPositivePrefixPattern())
2282 || AffixUtils.hasCurrencySymbols(tprops.getPositiveSuffixPattern())
2283 || AffixUtils.hasCurrencySymbols(tprops.getNegativePrefixPattern())
2284 || AffixUtils.hasCurrencySymbols(tprops.getNegativeSuffixPattern()));
2285 if (useCurrency) {
2286 tprops.setMinimumFractionDigits(exportedProperties.getMinimumFractionDigits());
2287 tprops.setMaximumFractionDigits(exportedProperties.getMaximumFractionDigits());
2288 tprops.setRoundingIncrement(exportedProperties.getRoundingIncrement());
2289 }
2290 return PatternStringUtils.propertiesToPatternString(tprops);
2291 }
2292
2293 /**
2294 * Calls {@link #toPattern} and converts the string to localized notation. For more information on
2295 * localized notation, see {@link #applyLocalizedPattern}. This method is provided for backwards
2296 * compatibility and should not be used in new projects.
2297 *
2298 * @return A decimal format pattern string in localized notation.
2299 */
toLocalizedPattern()2300 public synchronized String toLocalizedPattern() {
2301 String pattern = toPattern();
2302 return PatternStringUtils.convertLocalized(pattern, symbols, true);
2303 }
2304
2305 /**
2306 * Converts this DecimalFormat to a NumberFormatter. Starting in ICU 60,
2307 * NumberFormatter is the recommended way to format numbers.
2308 *
2309 * @return An instance of {@link LocalizedNumberFormatter} with the same behavior as this instance of
2310 * DecimalFormat.
2311 * @see NumberFormatter
2312 */
toNumberFormatter()2313 public LocalizedNumberFormatter toNumberFormatter() {
2314 return formatter;
2315 }
2316
2317 /**
2318 * @deprecated This API is ICU internal only.
2319 * @hide draft / provisional / internal are hidden on OHOS
2320 */
2321 @Deprecated
getFixedDecimal(double number)2322 public IFixedDecimal getFixedDecimal(double number) {
2323 return formatter.format(number).getFixedDecimal();
2324 }
2325
2326 /** Rebuilds the formatter object from the property bag. */
refreshFormatter()2327 void refreshFormatter() {
2328 if (exportedProperties == null) {
2329 // exportedProperties is null only when the formatter is not ready yet.
2330 // The only time when this happens is during legacy deserialization.
2331 return;
2332 }
2333 ULocale locale = this.getLocale(ULocale.ACTUAL_LOCALE);
2334 if (locale == null) {
2335 // Constructor
2336 locale = symbols.getLocale(ULocale.ACTUAL_LOCALE);
2337 }
2338 if (locale == null) {
2339 // Deserialization
2340 locale = symbols.getULocale();
2341 }
2342 assert locale != null;
2343 formatter = NumberFormatter.fromDecimalFormat(properties, symbols, exportedProperties).locale(locale);
2344
2345 // Lazy-initialize the parsers only when we need them.
2346 parser = null;
2347 currencyParser = null;
2348 }
2349
getParser()2350 NumberParserImpl getParser() {
2351 if (parser == null) {
2352 parser = NumberParserImpl.createParserFromProperties(properties, symbols, false);
2353 }
2354 return parser;
2355 }
2356
getCurrencyParser()2357 NumberParserImpl getCurrencyParser() {
2358 if (currencyParser == null) {
2359 currencyParser = NumberParserImpl.createParserFromProperties(properties, symbols, true);
2360 }
2361 return currencyParser;
2362 }
2363
2364 /**
2365 * Converts a java.math.BigDecimal to a ohos.global.icu.math.BigDecimal with fallback for numbers
2366 * outside of the range supported by ohos.global.icu.math.BigDecimal.
2367 *
2368 * @param number
2369 * @return
2370 */
safeConvertBigDecimal(java.math.BigDecimal number)2371 private Number safeConvertBigDecimal(java.math.BigDecimal number) {
2372 try {
2373 return new ohos.global.icu.math.BigDecimal(number);
2374 } catch (NumberFormatException e) {
2375 if (number.signum() > 0 && number.scale() < 0) {
2376 return Double.POSITIVE_INFINITY;
2377 } else if (number.scale() < 0) {
2378 return Double.NEGATIVE_INFINITY;
2379 } else if (number.signum() < 0) {
2380 return -0.0;
2381 } else {
2382 return 0.0;
2383 }
2384 }
2385 }
2386
2387 /**
2388 * Updates the property bag with settings from the given pattern.
2389 *
2390 * @param pattern The pattern string to parse.
2391 * @param ignoreRounding Whether to leave out rounding information (minFrac, maxFrac, and rounding
2392 * increment) when parsing the pattern. This may be desirable if a custom rounding mode, such
2393 * as CurrencyUsage, is to be used instead. One of {@link
2394 * PatternStringParser#IGNORE_ROUNDING_ALWAYS}, {@link PatternStringParser#IGNORE_ROUNDING_IF_CURRENCY},
2395 * or {@link PatternStringParser#IGNORE_ROUNDING_NEVER}.
2396 * @see PatternAndPropertyUtils#parseToExistingProperties
2397 */
setPropertiesFromPattern(String pattern, int ignoreRounding)2398 void setPropertiesFromPattern(String pattern, int ignoreRounding) {
2399 if (pattern == null) {
2400 throw new NullPointerException();
2401 }
2402 PatternStringParser.parseToExistingProperties(pattern, properties, ignoreRounding);
2403 }
2404
fieldPositionHelper( DecimalQuantity dq, FormattedStringBuilder string, FieldPosition fieldPosition, int offset)2405 static void fieldPositionHelper(
2406 DecimalQuantity dq, FormattedStringBuilder string, FieldPosition fieldPosition, int offset) {
2407 // always return first occurrence:
2408 fieldPosition.setBeginIndex(0);
2409 fieldPosition.setEndIndex(0);
2410 dq.populateUFieldPosition(fieldPosition);
2411 boolean found = FormattedValueStringBuilderImpl.nextFieldPosition(string, fieldPosition);;
2412 if (found && offset != 0) {
2413 fieldPosition.setBeginIndex(fieldPosition.getBeginIndex() + offset);
2414 fieldPosition.setEndIndex(fieldPosition.getEndIndex() + offset);
2415 }
2416 }
2417
2418 /**
2419 * @deprecated This API is ICU internal only.
2420 * @hide draft / provisional / internal are hidden on OHOS
2421 */
2422 @Deprecated
setProperties(PropertySetter func)2423 public synchronized void setProperties(PropertySetter func) {
2424 func.set(properties);
2425 refreshFormatter();
2426 }
2427
2428 /**
2429 * @deprecated This API is ICU internal only.
2430 * @hide exposed on OHOS
2431 * @hide draft / provisional / internal are hidden on OHOS
2432 */
2433 @Deprecated
2434 public static interface PropertySetter {
2435 /**
2436 * @deprecated This API is ICU internal only.
2437 * @hide draft / provisional / internal are hidden on OHOS
2438 */
2439 @Deprecated
set(DecimalFormatProperties props)2440 public void set(DecimalFormatProperties props);
2441 }
2442
2443 /**
2444 * <strong>[icu]</strong> Constant for {@link #getPadPosition()} and {@link #setPadPosition(int)} to specify pad
2445 * characters inserted before the prefix.
2446 *
2447 * @see #setPadPosition
2448 * @see #getPadPosition
2449 * @see #PAD_AFTER_PREFIX
2450 * @see #PAD_BEFORE_SUFFIX
2451 * @see #PAD_AFTER_SUFFIX
2452 */
2453 public static final int PAD_BEFORE_PREFIX = 0;
2454
2455 /**
2456 * <strong>[icu]</strong> Constant for {@link #getPadPosition()} and {@link #setPadPosition(int)} to specify pad
2457 * characters inserted after the prefix.
2458 *
2459 * @see #setPadPosition
2460 * @see #getPadPosition
2461 * @see #PAD_BEFORE_PREFIX
2462 * @see #PAD_BEFORE_SUFFIX
2463 * @see #PAD_AFTER_SUFFIX
2464 */
2465 public static final int PAD_AFTER_PREFIX = 1;
2466
2467 /**
2468 * <strong>[icu]</strong> Constant for {@link #getPadPosition()} and {@link #setPadPosition(int)} to specify pad
2469 * characters inserted before the suffix.
2470 *
2471 * @see #setPadPosition
2472 * @see #getPadPosition
2473 * @see #PAD_BEFORE_PREFIX
2474 * @see #PAD_AFTER_PREFIX
2475 * @see #PAD_AFTER_SUFFIX
2476 */
2477 public static final int PAD_BEFORE_SUFFIX = 2;
2478
2479 /**
2480 * <strong>[icu]</strong> Constant for {@link #getPadPosition()} and {@link #setPadPosition(int)} to specify pad
2481 * characters inserted after the suffix.
2482 *
2483 * @see #setPadPosition
2484 * @see #getPadPosition
2485 * @see #PAD_BEFORE_PREFIX
2486 * @see #PAD_AFTER_PREFIX
2487 * @see #PAD_BEFORE_SUFFIX
2488 */
2489 public static final int PAD_AFTER_SUFFIX = 3;
2490 }
2491