1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package java.util; 28 29 import android.compat.Compatibility; 30 import android.compat.annotation.ChangeId; 31 import android.compat.annotation.EnabledSince; 32 33 import dalvik.annotation.compat.VersionCodes; 34 import dalvik.system.VMRuntime; 35 36 import java.io.BufferedWriter; 37 import java.io.Closeable; 38 import java.io.IOException; 39 import java.io.File; 40 import java.io.FileOutputStream; 41 import java.io.FileNotFoundException; 42 import java.io.Flushable; 43 import java.io.OutputStream; 44 import java.io.OutputStreamWriter; 45 import java.io.PrintStream; 46 import java.io.UnsupportedEncodingException; 47 import java.math.BigDecimal; 48 import java.math.BigInteger; 49 import java.math.MathContext; 50 import java.math.RoundingMode; 51 import java.nio.charset.Charset; 52 import java.nio.charset.IllegalCharsetNameException; 53 import java.nio.charset.UnsupportedCharsetException; 54 import java.text.DateFormatSymbols; 55 import java.text.DecimalFormat; 56 import java.text.DecimalFormatSymbols; 57 import java.text.NumberFormat; 58 import java.time.DateTimeException; 59 import java.time.Instant; 60 import java.time.ZoneId; 61 import java.time.ZoneOffset; 62 import java.time.temporal.ChronoField; 63 import java.time.temporal.TemporalAccessor; 64 import java.time.temporal.TemporalQueries; 65 import java.time.temporal.UnsupportedTemporalTypeException; 66 67 import libcore.icu.DecimalFormatData; 68 import libcore.icu.LocaleData; 69 import jdk.internal.math.DoubleConsts; 70 import jdk.internal.math.FormattedFloatingDecimal; 71 72 // Android-changed: Use localized exponent separator for %e. 73 /** 74 * An interpreter for printf-style format strings. This class provides support 75 * for layout justification and alignment, common formats for numeric, string, 76 * and date/time data, and locale-specific output. Common Java types such as 77 * {@code byte}, {@link java.math.BigDecimal BigDecimal}, and {@link Calendar} 78 * are supported. Limited formatting customization for arbitrary user types is 79 * provided through the {@link Formattable} interface. 80 * 81 * <p> Formatters are not necessarily safe for multithreaded access. Thread 82 * safety is optional and is the responsibility of users of methods in this 83 * class. 84 * 85 * <p> Formatted printing for the Java language is heavily inspired by C's 86 * {@code printf}. Although the format strings are similar to C, some 87 * customizations have been made to accommodate the Java language and exploit 88 * some of its features. Also, Java formatting is more strict than C's; for 89 * example, if a conversion is incompatible with a flag, an exception will be 90 * thrown. In C inapplicable flags are silently ignored. The format strings 91 * are thus intended to be recognizable to C programmers but not necessarily 92 * completely compatible with those in C. 93 * 94 * <p> Examples of expected usage: 95 * 96 * <blockquote><pre> 97 * StringBuilder sb = new StringBuilder(); 98 * // Send all output to the Appendable object sb 99 * Formatter formatter = new Formatter(sb, Locale.US); 100 * 101 * // Explicit argument indices may be used to re-order output. 102 * formatter.format("%4$2s %3$2s %2$2s %1$2s", "a", "b", "c", "d") 103 * // -> " d c b a" 104 * 105 * // Optional locale as the first argument can be used to get 106 * // locale-specific formatting of numbers. The precision and width can be 107 * // given to round and align the value. 108 * formatter.format(Locale.FRANCE, "e = %+10.4f", Math.E); 109 * // -> "e = +2,7183" 110 * 111 * // The '(' numeric flag may be used to format negative numbers with 112 * // parentheses rather than a minus sign. Group separators are 113 * // automatically inserted. 114 * formatter.format("Amount gained or lost since last statement: $ %(,.2f", 115 * balanceDelta); 116 * // -> "Amount gained or lost since last statement: $ (6,217.58)" 117 * </pre></blockquote> 118 * 119 * <p> Convenience methods for common formatting requests exist as illustrated 120 * by the following invocations: 121 * 122 * <blockquote><pre> 123 * // Writes a formatted string to System.out. 124 * System.out.format("Local time: %tT", Calendar.getInstance()); 125 * // -> "Local time: 13:34:18" 126 * 127 * // Writes formatted output to System.err. 128 * System.err.printf("Unable to open file '%1$s': %2$s", 129 * fileName, exception.getMessage()); 130 * // -> "Unable to open file 'food': No such file or directory" 131 * </pre></blockquote> 132 * 133 * <p> Like C's {@code sprintf(3)}, Strings may be formatted using the static 134 * method {@link String#format(String,Object...) String.format}: 135 * 136 * <blockquote><pre> 137 * // Format a string containing a date. 138 * import java.util.Calendar; 139 * import java.util.GregorianCalendar; 140 * import static java.util.Calendar.*; 141 * 142 * Calendar c = new GregorianCalendar(1995, MAY, 23); 143 * String s = String.format("Duke's Birthday: %1$tb %1$te, %1$tY", c); 144 * // -> s == "Duke's Birthday: May 23, 1995" 145 * </pre></blockquote> 146 * 147 * <h2><a id="org">Organization</a></h2> 148 * 149 * <p> This specification is divided into two sections. The first section, <a 150 * href="#summary">Summary</a>, covers the basic formatting concepts. This 151 * section is intended for users who want to get started quickly and are 152 * familiar with formatted printing in other programming languages. The second 153 * section, <a href="#detail">Details</a>, covers the specific implementation 154 * details. It is intended for users who want more precise specification of 155 * formatting behavior. 156 * 157 * <h2><a id="summary">Summary</a></h2> 158 * 159 * <p> This section is intended to provide a brief overview of formatting 160 * concepts. For precise behavioral details, refer to the <a 161 * href="#detail">Details</a> section. 162 * 163 * <h3><a id="syntax">Format String Syntax</a></h3> 164 * 165 * <p> Every method which produces formatted output requires a <i>format 166 * string</i> and an <i>argument list</i>. The format string is a {@link 167 * String} which may contain fixed text and one or more embedded <i>format 168 * specifiers</i>. Consider the following example: 169 * 170 * <blockquote><pre> 171 * Calendar c = ...; 172 * String s = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c); 173 * </pre></blockquote> 174 * 175 * This format string is the first argument to the {@code format} method. It 176 * contains three format specifiers "{@code %1$tm}", "{@code %1$te}", and 177 * "{@code %1$tY}" which indicate how the arguments should be processed and 178 * where they should be inserted in the text. The remaining portions of the 179 * format string are fixed text including {@code "Dukes Birthday: "} and any 180 * other spaces or punctuation. 181 * 182 * The argument list consists of all arguments passed to the method after the 183 * format string. In the above example, the argument list is of size one and 184 * consists of the {@link java.util.Calendar Calendar} object {@code c}. 185 * 186 * <ul> 187 * 188 * <li> The format specifiers for general, character, and numeric types have 189 * the following syntax: 190 * 191 * <blockquote><pre> 192 * %[argument_index$][flags][width][.precision]conversion 193 * </pre></blockquote> 194 * 195 * <p> The optional <i>argument_index</i> is a decimal integer indicating the 196 * position of the argument in the argument list. The first argument is 197 * referenced by "{@code 1$}", the second by "{@code 2$}", etc. 198 * 199 * <p> The optional <i>flags</i> is a set of characters that modify the output 200 * format. The set of valid flags depends on the conversion. 201 * 202 * <p> The optional <i>width</i> is a positive decimal integer indicating 203 * the minimum number of characters to be written to the output. 204 * 205 * <p> The optional <i>precision</i> is a non-negative decimal integer usually 206 * used to restrict the number of characters. The specific behavior depends on 207 * the conversion. 208 * 209 * <p> The required <i>conversion</i> is a character indicating how the 210 * argument should be formatted. The set of valid conversions for a given 211 * argument depends on the argument's data type. 212 * 213 * <li> The format specifiers for types which are used to represents dates and 214 * times have the following syntax: 215 * 216 * <blockquote><pre> 217 * %[argument_index$][flags][width]conversion 218 * </pre></blockquote> 219 * 220 * <p> The optional <i>argument_index</i>, <i>flags</i> and <i>width</i> are 221 * defined as above. 222 * 223 * <p> The required <i>conversion</i> is a two character sequence. The first 224 * character is {@code 't'} or {@code 'T'}. The second character indicates 225 * the format to be used. These characters are similar to but not completely 226 * identical to those defined by GNU {@code date} and POSIX 227 * {@code strftime(3c)}. 228 * 229 * <li> The format specifiers which do not correspond to arguments have the 230 * following syntax: 231 * 232 * <blockquote><pre> 233 * %[flags][width]conversion 234 * </pre></blockquote> 235 * 236 * <p> The optional <i>flags</i> and <i>width</i> is defined as above. 237 * 238 * <p> The required <i>conversion</i> is a character indicating content to be 239 * inserted in the output. 240 * 241 * </ul> 242 * 243 * <h3> Conversions </h3> 244 * 245 * <p> Conversions are divided into the following categories: 246 * 247 * <ol> 248 * 249 * <li> <b>General</b> - may be applied to any argument 250 * type 251 * 252 * <li> <b>Character</b> - may be applied to basic types which represent 253 * Unicode characters: {@code char}, {@link Character}, {@code byte}, {@link 254 * Byte}, {@code short}, and {@link Short}. This conversion may also be 255 * applied to the types {@code int} and {@link Integer} when {@link 256 * Character#isValidCodePoint} returns {@code true} 257 * 258 * <li> <b>Numeric</b> 259 * 260 * <ol> 261 * 262 * <li> <b>Integral</b> - may be applied to Java integral types: {@code byte}, 263 * {@link Byte}, {@code short}, {@link Short}, {@code int} and {@link 264 * Integer}, {@code long}, {@link Long}, and {@link java.math.BigInteger 265 * BigInteger} (but not {@code char} or {@link Character}) 266 * 267 * <li><b>Floating Point</b> - may be applied to Java floating-point types: 268 * {@code float}, {@link Float}, {@code double}, {@link Double}, and {@link 269 * java.math.BigDecimal BigDecimal} 270 * 271 * </ol> 272 * 273 * <li> <b>Date/Time</b> - may be applied to Java types which are capable of 274 * encoding a date or time: {@code long}, {@link Long}, {@link Calendar}, 275 * {@link Date} and {@link TemporalAccessor TemporalAccessor} 276 * 277 * <li> <b>Percent</b> - produces a literal {@code '%'} 278 * (<code>'\u0025'</code>) 279 * 280 * <li> <b>Line Separator</b> - produces the platform-specific line separator 281 * 282 * </ol> 283 * 284 * <p> For category <i>General</i>, <i>Character</i>, <i>Numeric</i>, 285 * <i>Integral</i> and <i>Date/Time</i> conversion, unless otherwise specified, 286 * if the argument <i>arg</i> is {@code null}, then the result is "{@code null}". 287 * 288 * <p> The following table summarizes the supported conversions. Conversions 289 * denoted by an upper-case character (i.e. {@code 'B'}, {@code 'H'}, 290 * {@code 'S'}, {@code 'C'}, {@code 'X'}, {@code 'E'}, {@code 'G'}, 291 * {@code 'A'}, and {@code 'T'}) are the same as those for the corresponding 292 * lower-case conversion characters except that the result is converted to 293 * upper case according to the rules of the prevailing {@link java.util.Locale 294 * Locale}. If there is no explicit locale specified, either at the 295 * construction of the instance or as a parameter to its method 296 * invocation, then the {@link java.util.Locale.Category#FORMAT default locale} 297 * is used. 298 * 299 * 300 * <table class="striped"> 301 * <caption style="display:none">genConv</caption> 302 * <thead> 303 * <tr><th scope="col" style="vertical-align:bottom"> Conversion 304 * <th scope="col" style="vertical-align:bottom"> Argument Category 305 * <th scope="col" style="vertical-align:bottom"> Description 306 * </thead> 307 * <tbody> 308 * <tr><th scope="row" style="vertical-align:top"> {@code 'b'}, {@code 'B'} 309 * <td style="vertical-align:top"> general 310 * <td> If the argument <i>arg</i> is {@code null}, then the result is 311 * "{@code false}". If <i>arg</i> is a {@code boolean} or {@link 312 * Boolean}, then the result is the string returned by {@link 313 * String#valueOf(boolean) String.valueOf(arg)}. Otherwise, the result is 314 * "true". 315 * 316 * <tr><th scope="row" style="vertical-align:top"> {@code 'h'}, {@code 'H'} 317 * <td style="vertical-align:top"> general 318 * <td> The result is obtained by invoking 319 * {@code Integer.toHexString(arg.hashCode())}. 320 * 321 * <tr><th scope="row" style="vertical-align:top"> {@code 's'}, {@code 'S'} 322 * <td style="vertical-align:top"> general 323 * <td> If <i>arg</i> implements {@link Formattable}, then 324 * {@link Formattable#formatTo arg.formatTo} is invoked. Otherwise, the 325 * result is obtained by invoking {@code arg.toString()}. 326 * 327 * <tr><th scope="row" style="vertical-align:top">{@code 'c'}, {@code 'C'} 328 * <td style="vertical-align:top"> character 329 * <td> The result is a Unicode character 330 * 331 * <tr><th scope="row" style="vertical-align:top">{@code 'd'} 332 * <td style="vertical-align:top"> integral 333 * <td> The result is formatted as a decimal integer 334 * 335 * <tr><th scope="row" style="vertical-align:top">{@code 'o'} 336 * <td style="vertical-align:top"> integral 337 * <td> The result is formatted as an octal integer 338 * 339 * <tr><th scope="row" style="vertical-align:top">{@code 'x'}, {@code 'X'} 340 * <td style="vertical-align:top"> integral 341 * <td> The result is formatted as a hexadecimal integer 342 * 343 * <tr><th scope="row" style="vertical-align:top">{@code 'e'}, {@code 'E'} 344 * <td style="vertical-align:top"> floating point 345 * <td> The result is formatted as a decimal number in computerized 346 * scientific notation 347 * 348 * <tr><th scope="row" style="vertical-align:top">{@code 'f'} 349 * <td style="vertical-align:top"> floating point 350 * <td> The result is formatted as a decimal number 351 * 352 * <tr><th scope="row" style="vertical-align:top">{@code 'g'}, {@code 'G'} 353 * <td style="vertical-align:top"> floating point 354 * <td> The result is formatted using computerized scientific notation or 355 * decimal format, depending on the precision and the value after rounding. 356 * 357 * <tr><th scope="row" style="vertical-align:top">{@code 'a'}, {@code 'A'} 358 * <td style="vertical-align:top"> floating point 359 * <td> The result is formatted as a hexadecimal floating-point number with 360 * a significand and an exponent. This conversion is <b>not</b> supported 361 * for the {@code BigDecimal} type despite the latter's being in the 362 * <i>floating point</i> argument category. 363 * 364 * <tr><th scope="row" style="vertical-align:top">{@code 't'}, {@code 'T'} 365 * <td style="vertical-align:top"> date/time 366 * <td> Prefix for date and time conversion characters. See <a 367 * href="#dt">Date/Time Conversions</a>. 368 * 369 * <tr><th scope="row" style="vertical-align:top">{@code '%'} 370 * <td style="vertical-align:top"> percent 371 * <td> The result is a literal {@code '%'} (<code>'\u0025'</code>) 372 * 373 * <tr><th scope="row" style="vertical-align:top">{@code 'n'} 374 * <td style="vertical-align:top"> line separator 375 * <td> The result is the platform-specific line separator 376 * 377 * </tbody> 378 * </table> 379 * 380 * <p> Any characters not explicitly defined as conversions are illegal and are 381 * reserved for future extensions. 382 * 383 * <h3><a id="dt">Date/Time Conversions</a></h3> 384 * 385 * <p> The following date and time conversion suffix characters are defined for 386 * the {@code 't'} and {@code 'T'} conversions. The types are similar to but 387 * not completely identical to those defined by GNU {@code date} and POSIX 388 * {@code strftime(3c)}. Additional conversion types are provided to access 389 * Java-specific functionality (e.g. {@code 'L'} for milliseconds within the 390 * second). 391 * 392 * <p> The following conversion characters are used for formatting times: 393 * 394 * <table class="striped"> 395 * <caption style="display:none">time</caption> 396 * <tbody> 397 * <tr><th scope="row" style="vertical-align:top"> {@code 'H'} 398 * <td> Hour of the day for the 24-hour clock, formatted as two digits with 399 * a leading zero as necessary i.e. {@code 00 - 23}. 400 * 401 * <tr><th scope="row" style="vertical-align:top">{@code 'I'} 402 * <td> Hour for the 12-hour clock, formatted as two digits with a leading 403 * zero as necessary, i.e. {@code 01 - 12}. 404 * 405 * <tr><th scope="row" style="vertical-align:top">{@code 'k'} 406 * <td> Hour of the day for the 24-hour clock, i.e. {@code 0 - 23}. 407 * 408 * <tr><th scope="row" style="vertical-align:top">{@code 'l'} 409 * <td> Hour for the 12-hour clock, i.e. {@code 1 - 12}. 410 * 411 * <tr><th scope="row" style="vertical-align:top">{@code 'M'} 412 * <td> Minute within the hour formatted as two digits with a leading zero 413 * as necessary, i.e. {@code 00 - 59}. 414 * 415 * <tr><th scope="row" style="vertical-align:top">{@code 'S'} 416 * <td> Seconds within the minute, formatted as two digits with a leading 417 * zero as necessary, i.e. {@code 00 - 60} ("{@code 60}" is a special 418 * value required to support leap seconds). 419 * 420 * <tr><th scope="row" style="vertical-align:top">{@code 'L'} 421 * <td> Millisecond within the second formatted as three digits with 422 * leading zeros as necessary, i.e. {@code 000 - 999}. 423 * 424 * <tr><th scope="row" style="vertical-align:top">{@code 'N'} 425 * <td> Nanosecond within the second, formatted as nine digits with leading 426 * zeros as necessary, i.e. {@code 000000000 - 999999999}. 427 * 428 * <tr><th scope="row" style="vertical-align:top">{@code 'p'} 429 * <td> Locale-specific {@linkplain 430 * java.text.DateFormatSymbols#getAmPmStrings morning or afternoon} marker 431 * in lower case, e.g."{@code am}" or "{@code pm}". Use of the conversion 432 * prefix {@code 'T'} forces this output to upper case. 433 * 434 * <tr><th scope="row" style="vertical-align:top">{@code 'z'} 435 * <td> <a href="http://www.ietf.org/rfc/rfc0822.txt">RFC 822</a> 436 * style numeric time zone offset from GMT, e.g. {@code -0800}. This 437 * value will be adjusted as necessary for Daylight Saving Time. For 438 * {@code long}, {@link Long}, and {@link Date} the time zone used is 439 * the {@linkplain TimeZone#getDefault() default time zone} for this 440 * instance of the Java virtual machine. 441 * 442 * <tr><th scope="row" style="vertical-align:top">{@code 'Z'} 443 * <td> A string representing the abbreviation for the time zone. This 444 * value will be adjusted as necessary for Daylight Saving Time. For 445 * {@code long}, {@link Long}, and {@link Date} the time zone used is 446 * the {@linkplain TimeZone#getDefault() default time zone} for this 447 * instance of the Java virtual machine. The Formatter's locale will 448 * supersede the locale of the argument (if any). 449 * 450 * <tr><th scope="row" style="vertical-align:top">{@code 's'} 451 * <td> Seconds since the beginning of the epoch starting at 1 January 1970 452 * {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE/1000} to 453 * {@code Long.MAX_VALUE/1000}. 454 * 455 * <tr><th scope="row" style="vertical-align:top">{@code 'Q'} 456 * <td> Milliseconds since the beginning of the epoch starting at 1 January 457 * 1970 {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE} to 458 * {@code Long.MAX_VALUE}. 459 * 460 * </tbody> 461 * </table> 462 * 463 * <p> The following conversion characters are used for formatting dates: 464 * 465 * <table class="striped"> 466 * <caption style="display:none">date</caption> 467 * <tbody> 468 * 469 * <tr><th scope="row" style="vertical-align:top">{@code 'B'} 470 * <td> Locale-specific {@linkplain java.text.DateFormatSymbols#getMonths 471 * full month name}, e.g. {@code "January"}, {@code "February"}. 472 * 473 * <tr><th scope="row" style="vertical-align:top">{@code 'b'} 474 * <td> Locale-specific {@linkplain 475 * java.text.DateFormatSymbols#getShortMonths abbreviated month name}, 476 * e.g. {@code "Jan"}, {@code "Feb"}. 477 * 478 * <tr><th scope="row" style="vertical-align:top">{@code 'h'} 479 * <td> Same as {@code 'b'}. 480 * 481 * <tr><th scope="row" style="vertical-align:top">{@code 'A'} 482 * <td> Locale-specific full name of the {@linkplain 483 * java.text.DateFormatSymbols#getWeekdays day of the week}, 484 * e.g. {@code "Sunday"}, {@code "Monday"} 485 * 486 * <tr><th scope="row" style="vertical-align:top">{@code 'a'} 487 * <td> Locale-specific short name of the {@linkplain 488 * java.text.DateFormatSymbols#getShortWeekdays day of the week}, 489 * e.g. {@code "Sun"}, {@code "Mon"} 490 * 491 * <tr><th scope="row" style="vertical-align:top">{@code 'C'} 492 * <td> Four-digit year divided by {@code 100}, formatted as two digits 493 * with leading zero as necessary, i.e. {@code 00 - 99} 494 * 495 * <tr><th scope="row" style="vertical-align:top">{@code 'Y'} 496 * <td> Year, formatted as at least four digits with leading zeros as 497 * necessary, e.g. {@code 0092} equals {@code 92} CE for the Gregorian 498 * calendar. 499 * 500 * <tr><th scope="row" style="vertical-align:top">{@code 'y'} 501 * <td> Last two digits of the year, formatted with leading zeros as 502 * necessary, i.e. {@code 00 - 99}. 503 * 504 * <tr><th scope="row" style="vertical-align:top">{@code 'j'} 505 * <td> Day of year, formatted as three digits with leading zeros as 506 * necessary, e.g. {@code 001 - 366} for the Gregorian calendar. 507 * 508 * <tr><th scope="row" style="vertical-align:top">{@code 'm'} 509 * <td> Month, formatted as two digits with leading zeros as necessary, 510 * i.e. {@code 01 - 13}. 511 * 512 * <tr><th scope="row" style="vertical-align:top">{@code 'd'} 513 * <td> Day of month, formatted as two digits with leading zeros as 514 * necessary, i.e. {@code 01 - 31} 515 * 516 * <tr><th scope="row" style="vertical-align:top">{@code 'e'} 517 * <td> Day of month, formatted as two digits, i.e. {@code 1 - 31}. 518 * 519 * </tbody> 520 * </table> 521 * 522 * <p> The following conversion characters are used for formatting common 523 * date/time compositions. 524 * 525 * <table class="striped"> 526 * <caption style="display:none">composites</caption> 527 * <tbody> 528 * 529 * <tr><th scope="row" style="vertical-align:top">{@code 'R'} 530 * <td> Time formatted for the 24-hour clock as {@code "%tH:%tM"} 531 * 532 * <tr><th scope="row" style="vertical-align:top">{@code 'T'} 533 * <td> Time formatted for the 24-hour clock as {@code "%tH:%tM:%tS"}. 534 * 535 * <tr><th scope="row" style="vertical-align:top">{@code 'r'} 536 * <td> Time formatted for the 12-hour clock as {@code "%tI:%tM:%tS %Tp"}. 537 * The location of the morning or afternoon marker ({@code '%Tp'}) may be 538 * locale-dependent. 539 * 540 * <tr><th scope="row" style="vertical-align:top">{@code 'D'} 541 * <td> Date formatted as {@code "%tm/%td/%ty"}. 542 * 543 * <tr><th scope="row" style="vertical-align:top">{@code 'F'} 544 * <td> <a href="http://www.w3.org/TR/NOTE-datetime">ISO 8601</a> 545 * complete date formatted as {@code "%tY-%tm-%td"}. 546 * 547 * <tr><th scope="row" style="vertical-align:top">{@code 'c'} 548 * <td> Date and time formatted as {@code "%ta %tb %td %tT %tZ %tY"}, 549 * e.g. {@code "Sun Jul 20 16:17:00 EDT 1969"}. 550 * 551 * </tbody> 552 * </table> 553 * 554 * <p> Any characters not explicitly defined as date/time conversion suffixes 555 * are illegal and are reserved for future extensions. 556 * 557 * <h3> Flags </h3> 558 * 559 * <p> The following table summarizes the supported flags. <i>y</i> means the 560 * flag is supported for the indicated argument types. 561 * 562 * <table class="striped"> 563 * <caption style="display:none">genConv</caption> 564 * <thead> 565 * <tr><th scope="col" style="vertical-align:bottom"> Flag <th scope="col" style="vertical-align:bottom"> General 566 * <th scope="col" style="vertical-align:bottom"> Character <th scope="col" style="vertical-align:bottom"> Integral 567 * <th scope="col" style="vertical-align:bottom"> Floating Point 568 * <th scope="col" style="vertical-align:bottom"> Date/Time 569 * <th scope="col" style="vertical-align:bottom"> Description 570 * </thead> 571 * <tbody> 572 * <tr><th scope="row"> '-' <td style="text-align:center; vertical-align:top"> y 573 * <td style="text-align:center; vertical-align:top"> y 574 * <td style="text-align:center; vertical-align:top"> y 575 * <td style="text-align:center; vertical-align:top"> y 576 * <td style="text-align:center; vertical-align:top"> y 577 * <td> The result will be left-justified. 578 * 579 * <tr><th scope="row"> '#' <td style="text-align:center; vertical-align:top"> y<sup>1</sup> 580 * <td style="text-align:center; vertical-align:top"> - 581 * <td style="text-align:center; vertical-align:top"> y<sup>3</sup> 582 * <td style="text-align:center; vertical-align:top"> y 583 * <td style="text-align:center; vertical-align:top"> - 584 * <td> The result should use a conversion-dependent alternate form 585 * 586 * <tr><th scope="row"> '+' <td style="text-align:center; vertical-align:top"> - 587 * <td style="text-align:center; vertical-align:top"> - 588 * <td style="text-align:center; vertical-align:top"> y<sup>4</sup> 589 * <td style="text-align:center; vertical-align:top"> y 590 * <td style="text-align:center; vertical-align:top"> - 591 * <td> The result will always include a sign 592 * 593 * <tr><th scope="row"> ' ' <td style="text-align:center; vertical-align:top"> - 594 * <td style="text-align:center; vertical-align:top"> - 595 * <td style="text-align:center; vertical-align:top"> y<sup>4</sup> 596 * <td style="text-align:center; vertical-align:top"> y 597 * <td style="text-align:center; vertical-align:top"> - 598 * <td> The result will include a leading space for positive values 599 * 600 * <tr><th scope="row"> '0' <td style="text-align:center; vertical-align:top"> - 601 * <td style="text-align:center; vertical-align:top"> - 602 * <td style="text-align:center; vertical-align:top"> y 603 * <td style="text-align:center; vertical-align:top"> y 604 * <td style="text-align:center; vertical-align:top"> - 605 * <td> The result will be zero-padded 606 * 607 * <tr><th scope="row"> ',' <td style="text-align:center; vertical-align:top"> - 608 * <td style="text-align:center; vertical-align:top"> - 609 * <td style="text-align:center; vertical-align:top"> y<sup>2</sup> 610 * <td style="text-align:center; vertical-align:top"> y<sup>5</sup> 611 * <td style="text-align:center; vertical-align:top"> - 612 * <td> The result will include locale-specific {@linkplain 613 * java.text.DecimalFormatSymbols#getGroupingSeparator grouping separators} 614 * 615 * <tr><th scope="row"> '(' <td style="text-align:center; vertical-align:top"> - 616 * <td style="text-align:center; vertical-align:top"> - 617 * <td style="text-align:center; vertical-align:top"> y<sup>4</sup> 618 * <td style="text-align:center; vertical-align:top"> y<sup>5</sup> 619 * <td style="text-align:center"> - 620 * <td> The result will enclose negative numbers in parentheses 621 * 622 * </tbody> 623 * </table> 624 * 625 * <p> <sup>1</sup> Depends on the definition of {@link Formattable}. 626 * 627 * <p> <sup>2</sup> For {@code 'd'} conversion only. 628 * 629 * <p> <sup>3</sup> For {@code 'o'}, {@code 'x'}, and {@code 'X'} 630 * conversions only. 631 * 632 * <p> <sup>4</sup> For {@code 'd'}, {@code 'o'}, {@code 'x'}, and 633 * {@code 'X'} conversions applied to {@link java.math.BigInteger BigInteger} 634 * or {@code 'd'} applied to {@code byte}, {@link Byte}, {@code short}, {@link 635 * Short}, {@code int} and {@link Integer}, {@code long}, and {@link Long}. 636 * 637 * <p> <sup>5</sup> For {@code 'e'}, {@code 'E'}, {@code 'f'}, 638 * {@code 'g'}, and {@code 'G'} conversions only. 639 * 640 * <p> Any characters not explicitly defined as flags are illegal and are 641 * reserved for future extensions. 642 * 643 * <h3> Width </h3> 644 * 645 * <p> The width is the minimum number of characters to be written to the 646 * output. For the line separator conversion, width is not applicable; if it 647 * is provided, an exception will be thrown. 648 * 649 * <h3> Precision </h3> 650 * 651 * <p> For general argument types, the precision is the maximum number of 652 * characters to be written to the output. 653 * 654 * <p> For the floating-point conversions {@code 'a'}, {@code 'A'}, {@code 'e'}, 655 * {@code 'E'}, and {@code 'f'} the precision is the number of digits after the 656 * radix point. If the conversion is {@code 'g'} or {@code 'G'}, then the 657 * precision is the total number of digits in the resulting magnitude after 658 * rounding. 659 * 660 * <p> For character, integral, and date/time argument types and the percent 661 * and line separator conversions, the precision is not applicable; if a 662 * precision is provided, an exception will be thrown. 663 * 664 * <h3> Argument Index </h3> 665 * 666 * <p> The argument index is a decimal integer indicating the position of the 667 * argument in the argument list. The first argument is referenced by 668 * "{@code 1$}", the second by "{@code 2$}", etc. 669 * 670 * <p> Another way to reference arguments by position is to use the 671 * {@code '<'} (<code>'\u003c'</code>) flag, which causes the argument for 672 * the previous format specifier to be re-used. For example, the following two 673 * statements would produce identical strings: 674 * 675 * <blockquote><pre> 676 * Calendar c = ...; 677 * String s1 = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c); 678 * 679 * String s2 = String.format("Duke's Birthday: %1$tm %<te,%<tY", c); 680 * </pre></blockquote> 681 * 682 * <hr> 683 * <h2><a id="detail">Details</a></h2> 684 * 685 * <p> This section is intended to provide behavioral details for formatting, 686 * including conditions and exceptions, supported data types, localization, and 687 * interactions between flags, conversions, and data types. For an overview of 688 * formatting concepts, refer to the <a href="#summary">Summary</a> 689 * 690 * <p> Any characters not explicitly defined as conversions, date/time 691 * conversion suffixes, or flags are illegal and are reserved for 692 * future extensions. Use of such a character in a format string will 693 * cause an {@link UnknownFormatConversionException} or {@link 694 * UnknownFormatFlagsException} to be thrown. 695 * 696 * <p> If the format specifier contains a width or precision with an invalid 697 * value or which is otherwise unsupported, then a {@link 698 * IllegalFormatWidthException} or {@link IllegalFormatPrecisionException} 699 * respectively will be thrown. Similarly, values of zero for an argument 700 * index will result in an {@link IllegalFormatException}. 701 * 702 * <p> If a format specifier contains a conversion character that is not 703 * applicable to the corresponding argument, then an {@link 704 * IllegalFormatConversionException} will be thrown. 705 * 706 * <p> Values of <i>precision</i> must be in the range zero to 707 * {@link Integer#MAX_VALUE}, inclusive, otherwise 708 * {@link IllegalFormatPrecisionException} is thrown.</p> 709 * 710 * <p> Values of <i>width</i> must be in the range one to 711 * {@link Integer#MAX_VALUE}, inclusive, otherwise 712 * {@link IllegalFormatWidthException} will be thrown 713 * Note that widths can appear to have a negative value, but the negative sign 714 * is a <i>flag</i>. For example in the format string {@code "%-20s"} the 715 * <i>width</i> is <i>20</i> and the <i>flag</i> is "-".</p> 716 * 717 * <p> Values of <i>index</i> must be in the range one to 718 * {@link Integer#MAX_VALUE}, inclusive, otherwise 719 * {@link IllegalFormatException} will be thrown.</p> 720 * 721 * <p> All specified exceptions may be thrown by any of the {@code format} 722 * methods of {@code Formatter} as well as by any {@code format} convenience 723 * methods such as {@link String#format(String,Object...) String.format} and 724 * {@link java.io.PrintStream#printf(String,Object...) PrintStream.printf}. 725 * 726 * <p> For category <i>General</i>, <i>Character</i>, <i>Numeric</i>, 727 * <i>Integral</i> and <i>Date/Time</i> conversion, unless otherwise specified, 728 * if the argument <i>arg</i> is {@code null}, then the result is "{@code null}". 729 * 730 * <p> Conversions denoted by an upper-case character (i.e. {@code 'B'}, 731 * {@code 'H'}, {@code 'S'}, {@code 'C'}, {@code 'X'}, {@code 'E'}, 732 * {@code 'G'}, {@code 'A'}, and {@code 'T'}) are the same as those for the 733 * corresponding lower-case conversion characters except that the result is 734 * converted to upper case according to the rules of the prevailing {@link 735 * java.util.Locale Locale}. If there is no explicit locale specified, 736 * either at the construction of the instance or as a parameter to its method 737 * invocation, then the {@link java.util.Locale.Category#FORMAT default locale} 738 * is used. 739 * 740 * <h3><a id="dgen">General</a></h3> 741 * 742 * <p> The following general conversions may be applied to any argument type: 743 * 744 * <table class="striped"> 745 * <caption style="display:none">dgConv</caption> 746 * <tbody> 747 * 748 * <tr><th scope="row" style="vertical-align:top"> {@code 'b'} 749 * <td style="vertical-align:top"> <code>'\u0062'</code> 750 * <td> Produces either "{@code true}" or "{@code false}" as returned by 751 * {@link Boolean#toString(boolean)}. 752 * 753 * <p> If the argument is {@code null}, then the result is 754 * "{@code false}". If the argument is a {@code boolean} or {@link 755 * Boolean}, then the result is the string returned by {@link 756 * String#valueOf(boolean) String.valueOf()}. Otherwise, the result is 757 * "{@code true}". 758 * 759 * <p> If the {@code '#'} flag is given, then a {@link 760 * FormatFlagsConversionMismatchException} will be thrown. 761 * 762 * <tr><th scope="row" style="vertical-align:top"> {@code 'B'} 763 * <td style="vertical-align:top"> <code>'\u0042'</code> 764 * <td> The upper-case variant of {@code 'b'}. 765 * 766 * <tr><th scope="row" style="vertical-align:top"> {@code 'h'} 767 * <td style="vertical-align:top"> <code>'\u0068'</code> 768 * <td> Produces a string representing the hash code value of the object. 769 * 770 * <p> The result is obtained by invoking 771 * {@code Integer.toHexString(arg.hashCode())}. 772 * 773 * <p> If the {@code '#'} flag is given, then a {@link 774 * FormatFlagsConversionMismatchException} will be thrown. 775 * 776 * <tr><th scope="row" style="vertical-align:top"> {@code 'H'} 777 * <td style="vertical-align:top"> <code>'\u0048'</code> 778 * <td> The upper-case variant of {@code 'h'}. 779 * 780 * <tr><th scope="row" style="vertical-align:top"> {@code 's'} 781 * <td style="vertical-align:top"> <code>'\u0073'</code> 782 * <td> Produces a string. 783 * 784 * <p> If the argument implements {@link Formattable}, then 785 * its {@link Formattable#formatTo formatTo} method is invoked. 786 * Otherwise, the result is obtained by invoking the argument's 787 * {@code toString()} method. 788 * 789 * <p> If the {@code '#'} flag is given and the argument is not a {@link 790 * Formattable}, then a {@link FormatFlagsConversionMismatchException} 791 * will be thrown. 792 * 793 * <tr><th scope="row" style="vertical-align:top"> {@code 'S'} 794 * <td style="vertical-align:top"> <code>'\u0053'</code> 795 * <td> The upper-case variant of {@code 's'}. 796 * 797 * </tbody> 798 * </table> 799 * 800 * <p> The following <a id="dFlags">flags</a> apply to general conversions: 801 * 802 * <table class="striped"> 803 * <caption style="display:none">dFlags</caption> 804 * <tbody> 805 * 806 * <tr><th scope="row" style="vertical-align:top"> {@code '-'} 807 * <td style="vertical-align:top"> <code>'\u002d'</code> 808 * <td> Left justifies the output. Spaces (<code>'\u0020'</code>) will be 809 * added at the end of the converted value as required to fill the minimum 810 * width of the field. If the width is not provided, then a {@link 811 * MissingFormatWidthException} will be thrown. If this flag is not given 812 * then the output will be right-justified. 813 * 814 * <tr><th scope="row" style="vertical-align:top"> {@code '#'} 815 * <td style="vertical-align:top"> <code>'\u0023'</code> 816 * <td> Requires the output use an alternate form. The definition of the 817 * form is specified by the conversion. 818 * 819 * </tbody> 820 * </table> 821 * 822 * <p> The <a id="genWidth">width</a> is the minimum number of characters to 823 * be written to the 824 * output. If the length of the converted value is less than the width then 825 * the output will be padded by <code>' '</code> (<code>'\u0020'</code>) 826 * until the total number of characters equals the width. The padding is on 827 * the left by default. If the {@code '-'} flag is given, then the padding 828 * will be on the right. If the width is not specified then there is no 829 * minimum. 830 * 831 * <p> The precision is the maximum number of characters to be written to the 832 * output. The precision is applied before the width, thus the output will be 833 * truncated to {@code precision} characters even if the width is greater than 834 * the precision. If the precision is not specified then there is no explicit 835 * limit on the number of characters. 836 * 837 * <h3><a id="dchar">Character</a></h3> 838 * 839 * This conversion may be applied to {@code char} and {@link Character}. It 840 * may also be applied to the types {@code byte}, {@link Byte}, 841 * {@code short}, and {@link Short}, {@code int} and {@link Integer} when 842 * {@link Character#isValidCodePoint} returns {@code true}. If it returns 843 * {@code false} then an {@link IllegalFormatCodePointException} will be 844 * thrown. 845 * 846 * <table class="striped"> 847 * <caption style="display:none">charConv</caption> 848 * <tbody> 849 * 850 * <tr><th scope="row" style="vertical-align:top"> {@code 'c'} 851 * <td style="vertical-align:top"> <code>'\u0063'</code> 852 * <td> Formats the argument as a Unicode character as described in <a 853 * href="../lang/Character.html#unicode">Unicode Character 854 * Representation</a>. This may be more than one 16-bit {@code char} in 855 * the case where the argument represents a supplementary character. 856 * 857 * <p> If the {@code '#'} flag is given, then a {@link 858 * FormatFlagsConversionMismatchException} will be thrown. 859 * 860 * <tr><th scope="row" style="vertical-align:top"> {@code 'C'} 861 * <td style="vertical-align:top"> <code>'\u0043'</code> 862 * <td> The upper-case variant of {@code 'c'}. 863 * 864 * </tbody> 865 * </table> 866 * 867 * <p> The {@code '-'} flag defined for <a href="#dFlags">General 868 * conversions</a> applies. If the {@code '#'} flag is given, then a {@link 869 * FormatFlagsConversionMismatchException} will be thrown. 870 * 871 * <p> The width is defined as for <a href="#genWidth">General conversions</a>. 872 * 873 * <p> The precision is not applicable. If the precision is specified then an 874 * {@link IllegalFormatPrecisionException} will be thrown. 875 * 876 * <h3><a id="dnum">Numeric</a></h3> 877 * 878 * <p> Numeric conversions are divided into the following categories: 879 * 880 * <ol> 881 * 882 * <li> <a href="#dnint"><b>Byte, Short, Integer, and Long</b></a> 883 * 884 * <li> <a href="#dnbint"><b>BigInteger</b></a> 885 * 886 * <li> <a href="#dndec"><b>Float and Double</b></a> 887 * 888 * <li> <a href="#dnbdec"><b>BigDecimal</b></a> 889 * 890 * </ol> 891 * 892 * <p> Numeric types will be formatted according to the following algorithm: 893 * 894 * <p><b><a id="L10nAlgorithm"> Number Localization Algorithm</a></b> 895 * 896 * <p> After digits are obtained for the integer part, fractional part, and 897 * exponent (as appropriate for the data type), the following transformation 898 * is applied: 899 * 900 * <ol> 901 * 902 * <li> Each digit character <i>d</i> in the string is replaced by a 903 * locale-specific digit computed relative to the current locale's 904 * {@linkplain java.text.DecimalFormatSymbols#getZeroDigit() zero digit} 905 * <i>z</i>; that is <i>d - </i> {@code '0'} 906 * <i> + z</i>. 907 * 908 * <li> If a decimal separator is present, a locale-specific {@linkplain 909 * java.text.DecimalFormatSymbols#getDecimalSeparator decimal separator} is 910 * substituted. 911 * 912 * <li> If the {@code ','} (<code>'\u002c'</code>) 913 * <a id="L10nGroup">flag</a> is given, then the locale-specific {@linkplain 914 * java.text.DecimalFormatSymbols#getGroupingSeparator grouping separator} is 915 * inserted by scanning the integer part of the string from least significant 916 * to most significant digits and inserting a separator at intervals defined by 917 * the locale's {@linkplain java.text.DecimalFormat#getGroupingSize() grouping 918 * size}. 919 * 920 * <li> If the {@code '0'} flag is given, then the locale-specific {@linkplain 921 * java.text.DecimalFormatSymbols#getZeroDigit() zero digits} are inserted 922 * after the sign character, if any, and before the first non-zero digit, until 923 * the length of the string is equal to the requested field width. 924 * 925 * <li> If the value is negative and the {@code '('} flag is given, then a 926 * {@code '('} (<code>'\u0028'</code>) is prepended and a {@code ')'} 927 * (<code>'\u0029'</code>) is appended. 928 * 929 * <li> If the value is negative (or floating-point negative zero) and 930 * {@code '('} flag is not given, then a {@code '-'} (<code>'\u002d'</code>) 931 * is prepended. 932 * 933 * <li> If the {@code '+'} flag is given and the value is positive or zero (or 934 * floating-point positive zero), then a {@code '+'} (<code>'\u002b'</code>) 935 * will be prepended. 936 * 937 * </ol> 938 * 939 * <p> If the value is NaN or positive infinity the literal strings "NaN" or 940 * "Infinity" respectively, will be output. If the value is negative infinity, 941 * then the output will be "(Infinity)" if the {@code '('} flag is given 942 * otherwise the output will be "-Infinity". These values are not localized. 943 * 944 * <p><a id="dnint"><b> Byte, Short, Integer, and Long </b></a> 945 * 946 * <p> The following conversions may be applied to {@code byte}, {@link Byte}, 947 * {@code short}, {@link Short}, {@code int} and {@link Integer}, 948 * {@code long}, and {@link Long}. 949 * 950 * <table class="striped"> 951 * <caption style="display:none">IntConv</caption> 952 * <tbody> 953 * 954 * <tr><th scope="row" style="vertical-align:top"> {@code 'd'} 955 * <td style="vertical-align:top"> <code>'\u0064'</code> 956 * <td> Formats the argument as a decimal integer. The <a 957 * href="#L10nAlgorithm">localization algorithm</a> is applied. 958 * 959 * <p> If the {@code '0'} flag is given and the value is negative, then 960 * the zero padding will occur after the sign. 961 * 962 * <p> If the {@code '#'} flag is given then a {@link 963 * FormatFlagsConversionMismatchException} will be thrown. 964 * 965 * <tr><th scope="row" style="vertical-align:top"> {@code 'o'} 966 * <td style="vertical-align:top"> <code>'\u006f'</code> 967 * <td> Formats the argument as an integer in base eight. No localization 968 * is applied. 969 * 970 * <p> If <i>x</i> is negative then the result will be an unsigned value 971 * generated by adding 2<sup>n</sup> to the value where {@code n} is the 972 * number of bits in the type as returned by the static {@code SIZE} field 973 * in the {@linkplain Byte#SIZE Byte}, {@linkplain Short#SIZE Short}, 974 * {@linkplain Integer#SIZE Integer}, or {@linkplain Long#SIZE Long} 975 * classes as appropriate. 976 * 977 * <p> If the {@code '#'} flag is given then the output will always begin 978 * with the radix indicator {@code '0'}. 979 * 980 * <p> If the {@code '0'} flag is given then the output will be padded 981 * with leading zeros to the field width following any indication of sign. 982 * 983 * <p> If {@code '('}, {@code '+'}, ' ', or {@code ','} flags 984 * are given then a {@link FormatFlagsConversionMismatchException} will be 985 * thrown. 986 * 987 * <tr><th scope="row" style="vertical-align:top"> {@code 'x'} 988 * <td style="vertical-align:top"> <code>'\u0078'</code> 989 * <td> Formats the argument as an integer in base sixteen. No 990 * localization is applied. 991 * 992 * <p> If <i>x</i> is negative then the result will be an unsigned value 993 * generated by adding 2<sup>n</sup> to the value where {@code n} is the 994 * number of bits in the type as returned by the static {@code SIZE} field 995 * in the {@linkplain Byte#SIZE Byte}, {@linkplain Short#SIZE Short}, 996 * {@linkplain Integer#SIZE Integer}, or {@linkplain Long#SIZE Long} 997 * classes as appropriate. 998 * 999 * <p> If the {@code '#'} flag is given then the output will always begin 1000 * with the radix indicator {@code "0x"}. 1001 * 1002 * <p> If the {@code '0'} flag is given then the output will be padded to 1003 * the field width with leading zeros after the radix indicator or sign (if 1004 * present). 1005 * 1006 * <p> If {@code '('}, <code>' '</code>, {@code '+'}, or 1007 * {@code ','} flags are given then a {@link 1008 * FormatFlagsConversionMismatchException} will be thrown. 1009 * 1010 * <tr><th scope="row" style="vertical-align:top"> {@code 'X'} 1011 * <td style="vertical-align:top"> <code>'\u0058'</code> 1012 * <td> The upper-case variant of {@code 'x'}. The entire string 1013 * representing the number will be converted to {@linkplain 1014 * String#toUpperCase upper case} including the {@code 'x'} (if any) and 1015 * all hexadecimal digits {@code 'a'} - {@code 'f'} 1016 * (<code>'\u0061'</code> - <code>'\u0066'</code>). 1017 * 1018 * </tbody> 1019 * </table> 1020 * 1021 * <p> If the conversion is {@code 'o'}, {@code 'x'}, or {@code 'X'} and 1022 * both the {@code '#'} and the {@code '0'} flags are given, then result will 1023 * contain the radix indicator ({@code '0'} for octal and {@code "0x"} or 1024 * {@code "0X"} for hexadecimal), some number of zeros (based on the width), 1025 * and the value. 1026 * 1027 * <p> If the {@code '-'} flag is not given, then the space padding will occur 1028 * before the sign. 1029 * 1030 * <p> The following <a id="intFlags">flags</a> apply to numeric integral 1031 * conversions: 1032 * 1033 * <table class="striped"> 1034 * <caption style="display:none">intFlags</caption> 1035 * <tbody> 1036 * 1037 * <tr><th scope="row" style="vertical-align:top"> {@code '+'} 1038 * <td style="vertical-align:top"> <code>'\u002b'</code> 1039 * <td> Requires the output to include a positive sign for all positive 1040 * numbers. If this flag is not given then only negative values will 1041 * include a sign. 1042 * 1043 * <p> If both the {@code '+'} and <code>' '</code> flags are given 1044 * then an {@link IllegalFormatFlagsException} will be thrown. 1045 * 1046 * <tr><th scope="row" style="vertical-align:top"> <code>' '</code> 1047 * <td style="vertical-align:top"> <code>'\u0020'</code> 1048 * <td> Requires the output to include a single extra space 1049 * (<code>'\u0020'</code>) for non-negative values. 1050 * 1051 * <p> If both the {@code '+'} and <code>' '</code> flags are given 1052 * then an {@link IllegalFormatFlagsException} will be thrown. 1053 * 1054 * <tr><th scope="row" style="vertical-align:top"> {@code '0'} 1055 * <td style="vertical-align:top"> <code>'\u0030'</code> 1056 * <td> Requires the output to be padded with leading {@linkplain 1057 * java.text.DecimalFormatSymbols#getZeroDigit zeros} to the minimum field 1058 * width following any sign or radix indicator except when converting NaN 1059 * or infinity. If the width is not provided, then a {@link 1060 * MissingFormatWidthException} will be thrown. 1061 * 1062 * <p> If both the {@code '-'} and {@code '0'} flags are given then an 1063 * {@link IllegalFormatFlagsException} will be thrown. 1064 * 1065 * <tr><th scope="row" style="vertical-align:top"> {@code ','} 1066 * <td style="vertical-align:top"> <code>'\u002c'</code> 1067 * <td> Requires the output to include the locale-specific {@linkplain 1068 * java.text.DecimalFormatSymbols#getGroupingSeparator group separators} as 1069 * described in the <a href="#L10nGroup">"group" section</a> of the 1070 * localization algorithm. 1071 * 1072 * <tr><th scope="row" style="vertical-align:top"> {@code '('} 1073 * <td style="vertical-align:top"> <code>'\u0028'</code> 1074 * <td> Requires the output to prepend a {@code '('} 1075 * (<code>'\u0028'</code>) and append a {@code ')'} 1076 * (<code>'\u0029'</code>) to negative values. 1077 * 1078 * </tbody> 1079 * </table> 1080 * 1081 * <p> If no <a id="intdFlags">flags</a> are given the default formatting is 1082 * as follows: 1083 * 1084 * <ul> 1085 * 1086 * <li> The output is right-justified within the {@code width} 1087 * 1088 * <li> Negative numbers begin with a {@code '-'} (<code>'\u002d'</code>) 1089 * 1090 * <li> Positive numbers and zero do not include a sign or extra leading 1091 * space 1092 * 1093 * <li> No grouping separators are included 1094 * 1095 * </ul> 1096 * 1097 * <p> The <a id="intWidth">width</a> is the minimum number of characters to 1098 * be written to the output. This includes any signs, digits, grouping 1099 * separators, radix indicator, and parentheses. If the length of the 1100 * converted value is less than the width then the output will be padded by 1101 * spaces (<code>'\u0020'</code>) until the total number of characters equals 1102 * width. The padding is on the left by default. If {@code '-'} flag is 1103 * given then the padding will be on the right. If width is not specified then 1104 * there is no minimum. 1105 * 1106 * <p> The precision is not applicable. If precision is specified then an 1107 * {@link IllegalFormatPrecisionException} will be thrown. 1108 * 1109 * <p><a id="dnbint"><b> BigInteger </b></a> 1110 * 1111 * <p> The following conversions may be applied to {@link 1112 * java.math.BigInteger}. 1113 * 1114 * <table class="striped"> 1115 * <caption style="display:none">bIntConv</caption> 1116 * <tbody> 1117 * 1118 * <tr><th scope="row" style="vertical-align:top"> {@code 'd'} 1119 * <td style="vertical-align:top"> <code>'\u0064'</code> 1120 * <td> Requires the output to be formatted as a decimal integer. The <a 1121 * href="#L10nAlgorithm">localization algorithm</a> is applied. 1122 * 1123 * <p> If the {@code '#'} flag is given {@link 1124 * FormatFlagsConversionMismatchException} will be thrown. 1125 * 1126 * <tr><th scope="row" style="vertical-align:top"> {@code 'o'} 1127 * <td style="vertical-align:top"> <code>'\u006f'</code> 1128 * <td> Requires the output to be formatted as an integer in base eight. 1129 * No localization is applied. 1130 * 1131 * <p> If <i>x</i> is negative then the result will be a signed value 1132 * beginning with {@code '-'} (<code>'\u002d'</code>). Signed output is 1133 * allowed for this type because unlike the primitive types it is not 1134 * possible to create an unsigned equivalent without assuming an explicit 1135 * data-type size. 1136 * 1137 * <p> If <i>x</i> is positive or zero and the {@code '+'} flag is given 1138 * then the result will begin with {@code '+'} (<code>'\u002b'</code>). 1139 * 1140 * <p> If the {@code '#'} flag is given then the output will always begin 1141 * with {@code '0'} prefix. 1142 * 1143 * <p> If the {@code '0'} flag is given then the output will be padded 1144 * with leading zeros to the field width following any indication of sign. 1145 * 1146 * <p> If the {@code ','} flag is given then a {@link 1147 * FormatFlagsConversionMismatchException} will be thrown. 1148 * 1149 * <tr><th scope="row" style="vertical-align:top"> {@code 'x'} 1150 * <td style="vertical-align:top"> <code>'\u0078'</code> 1151 * <td> Requires the output to be formatted as an integer in base 1152 * sixteen. No localization is applied. 1153 * 1154 * <p> If <i>x</i> is negative then the result will be a signed value 1155 * beginning with {@code '-'} (<code>'\u002d'</code>). Signed output is 1156 * allowed for this type because unlike the primitive types it is not 1157 * possible to create an unsigned equivalent without assuming an explicit 1158 * data-type size. 1159 * 1160 * <p> If <i>x</i> is positive or zero and the {@code '+'} flag is given 1161 * then the result will begin with {@code '+'} (<code>'\u002b'</code>). 1162 * 1163 * <p> If the {@code '#'} flag is given then the output will always begin 1164 * with the radix indicator {@code "0x"}. 1165 * 1166 * <p> If the {@code '0'} flag is given then the output will be padded to 1167 * the field width with leading zeros after the radix indicator or sign (if 1168 * present). 1169 * 1170 * <p> If the {@code ','} flag is given then a {@link 1171 * FormatFlagsConversionMismatchException} will be thrown. 1172 * 1173 * <tr><th scope="row" style="vertical-align:top"> {@code 'X'} 1174 * <td style="vertical-align:top"> <code>'\u0058'</code> 1175 * <td> The upper-case variant of {@code 'x'}. The entire string 1176 * representing the number will be converted to {@linkplain 1177 * String#toUpperCase upper case} including the {@code 'x'} (if any) and 1178 * all hexadecimal digits {@code 'a'} - {@code 'f'} 1179 * (<code>'\u0061'</code> - <code>'\u0066'</code>). 1180 * 1181 * </tbody> 1182 * </table> 1183 * 1184 * <p> If the conversion is {@code 'o'}, {@code 'x'}, or {@code 'X'} and 1185 * both the {@code '#'} and the {@code '0'} flags are given, then result will 1186 * contain the base indicator ({@code '0'} for octal and {@code "0x"} or 1187 * {@code "0X"} for hexadecimal), some number of zeros (based on the width), 1188 * and the value. 1189 * 1190 * <p> If the {@code '0'} flag is given and the value is negative, then the 1191 * zero padding will occur after the sign. 1192 * 1193 * <p> If the {@code '-'} flag is not given, then the space padding will occur 1194 * before the sign. 1195 * 1196 * <p> All <a href="#intFlags">flags</a> defined for Byte, Short, Integer, and 1197 * Long apply. The <a href="#intdFlags">default behavior</a> when no flags are 1198 * given is the same as for Byte, Short, Integer, and Long. 1199 * 1200 * <p> The specification of <a href="#intWidth">width</a> is the same as 1201 * defined for Byte, Short, Integer, and Long. 1202 * 1203 * <p> The precision is not applicable. If precision is specified then an 1204 * {@link IllegalFormatPrecisionException} will be thrown. 1205 * 1206 * <p><a id="dndec"><b> Float and Double</b></a> 1207 * 1208 * <p> The following conversions may be applied to {@code float}, {@link 1209 * Float}, {@code double} and {@link Double}. 1210 * 1211 * <table class="striped"> 1212 * <caption style="display:none">floatConv</caption> 1213 * <tbody> 1214 * 1215 * <tr><th scope="row" style="vertical-align:top"> {@code 'e'} 1216 * <td style="vertical-align:top"> <code>'\u0065'</code> 1217 * <td> Requires the output to be formatted using <a 1218 * id="scientific">computerized scientific notation</a>. The <a 1219 * href="#L10nAlgorithm">localization algorithm</a> is applied. 1220 * 1221 * <p> The formatting of the magnitude <i>m</i> depends upon its value. 1222 * 1223 * <p> If <i>m</i> is NaN or infinite, the literal strings "NaN" or 1224 * "Infinity", respectively, will be output. These values are not 1225 * localized. 1226 * 1227 * <p> If <i>m</i> is positive-zero or negative-zero, then the exponent 1228 * will be {@code "+00"}. 1229 * 1230 * <p> Otherwise, the result is a string that represents the sign and 1231 * magnitude (absolute value) of the argument. The formatting of the sign 1232 * is described in the <a href="#L10nAlgorithm">localization 1233 * algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its 1234 * value. 1235 * 1236 * <p> Let <i>n</i> be the unique integer such that 10<sup><i>n</i></sup> 1237 * <= <i>m</i> < 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the 1238 * mathematically exact quotient of <i>m</i> and 10<sup><i>n</i></sup> so 1239 * that 1 <= <i>a</i> < 10. The magnitude is then represented as the 1240 * integer part of <i>a</i>, as a single decimal digit, followed by the 1241 * decimal separator followed by decimal digits representing the fractional 1242 * part of <i>a</i>, followed by the lower-case locale-specific {@linkplain 1243 * java.text.DecimalFormatSymbols#getExponentSeparator exponent separator} 1244 * (e.g. {@code 'e'}), followed by the sign of the exponent, followed 1245 * by a representation of <i>n</i> as a decimal integer, as produced by the 1246 * method {@link Long#toString(long, int)}, and zero-padded to include at 1247 * least two digits. 1248 * 1249 * <p> The number of digits in the result for the fractional part of 1250 * <i>m</i> or <i>a</i> is equal to the precision. If the precision is not 1251 * specified then the default value is {@code 6}. If the precision is less 1252 * than the number of digits which would appear after the decimal point in 1253 * the string returned by {@link Float#toString(float)} or {@link 1254 * Double#toString(double)} respectively, then the value will be rounded 1255 * using the {@linkplain java.math.RoundingMode#HALF_UP round half up 1256 * algorithm}. Otherwise, zeros may be appended to reach the precision. 1257 * For a canonical representation of the value, use {@link 1258 * Float#toString(float)} or {@link Double#toString(double)} as 1259 * appropriate. 1260 * 1261 * <p>If the {@code ','} flag is given, then an {@link 1262 * FormatFlagsConversionMismatchException} will be thrown. 1263 * 1264 * <tr><th scope="row" style="vertical-align:top"> {@code 'E'} 1265 * <td style="vertical-align:top"> <code>'\u0045'</code> 1266 * <td> The upper-case variant of {@code 'e'}. The exponent symbol 1267 * will be the upper-case locale-specific {@linkplain 1268 * java.text.DecimalFormatSymbols#getExponentSeparator exponent separator} 1269 * (e.g. {@code 'E'}). 1270 * 1271 * <tr><th scope="row" style="vertical-align:top"> {@code 'g'} 1272 * <td style="vertical-align:top"> <code>'\u0067'</code> 1273 * <td> Requires the output to be formatted in general scientific notation 1274 * as described below. The <a href="#L10nAlgorithm">localization 1275 * algorithm</a> is applied. 1276 * 1277 * <p> After rounding for the precision, the formatting of the resulting 1278 * magnitude <i>m</i> depends on its value. 1279 * 1280 * <p> If <i>m</i> is greater than or equal to 10<sup>-4</sup> but less 1281 * than 10<sup>precision</sup> then it is represented in <i><a 1282 * href="#decimal">decimal format</a></i>. 1283 * 1284 * <p> If <i>m</i> is less than 10<sup>-4</sup> or greater than or equal to 1285 * 10<sup>precision</sup>, then it is represented in <i><a 1286 * href="#scientific">computerized scientific notation</a></i>. 1287 * 1288 * <p> The total number of significant digits in <i>m</i> is equal to the 1289 * precision. If the precision is not specified, then the default value is 1290 * {@code 6}. If the precision is {@code 0}, then it is taken to be 1291 * {@code 1}. 1292 * 1293 * <p> If the {@code '#'} flag is given then an {@link 1294 * FormatFlagsConversionMismatchException} will be thrown. 1295 * 1296 * <tr><th scope="row" style="vertical-align:top"> {@code 'G'} 1297 * <td style="vertical-align:top"> <code>'\u0047'</code> 1298 * <td> The upper-case variant of {@code 'g'}. 1299 * 1300 * <tr><th scope="row" style="vertical-align:top"> {@code 'f'} 1301 * <td style="vertical-align:top"> <code>'\u0066'</code> 1302 * <td> Requires the output to be formatted using <a id="decimal">decimal 1303 * format</a>. The <a href="#L10nAlgorithm">localization algorithm</a> is 1304 * applied. 1305 * 1306 * <p> The result is a string that represents the sign and magnitude 1307 * (absolute value) of the argument. The formatting of the sign is 1308 * described in the <a href="#L10nAlgorithm">localization 1309 * algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its 1310 * value. 1311 * 1312 * <p> If <i>m</i> NaN or infinite, the literal strings "NaN" or 1313 * "Infinity", respectively, will be output. These values are not 1314 * localized. 1315 * 1316 * <p> The magnitude is formatted as the integer part of <i>m</i>, with no 1317 * leading zeroes, followed by the decimal separator followed by one or 1318 * more decimal digits representing the fractional part of <i>m</i>. 1319 * 1320 * <p> The number of digits in the result for the fractional part of 1321 * <i>m</i> or <i>a</i> is equal to the precision. If the precision is not 1322 * specified then the default value is {@code 6}. If the precision is less 1323 * than the number of digits which would appear after the decimal point in 1324 * the string returned by {@link Float#toString(float)} or {@link 1325 * Double#toString(double)} respectively, then the value will be rounded 1326 * using the {@linkplain java.math.RoundingMode#HALF_UP round half up 1327 * algorithm}. Otherwise, zeros may be appended to reach the precision. 1328 * For a canonical representation of the value, use {@link 1329 * Float#toString(float)} or {@link Double#toString(double)} as 1330 * appropriate. 1331 * 1332 * <tr><th scope="row" style="vertical-align:top"> {@code 'a'} 1333 * <td style="vertical-align:top"> <code>'\u0061'</code> 1334 * <td> Requires the output to be formatted in hexadecimal exponential 1335 * form. No localization is applied. 1336 * 1337 * <p> The result is a string that represents the sign and magnitude 1338 * (absolute value) of the argument <i>x</i>. 1339 * 1340 * <p> If <i>x</i> is negative or a negative-zero value then the result 1341 * will begin with {@code '-'} (<code>'\u002d'</code>). 1342 * 1343 * <p> If <i>x</i> is positive or a positive-zero value and the 1344 * {@code '+'} flag is given then the result will begin with {@code '+'} 1345 * (<code>'\u002b'</code>). 1346 * 1347 * <p> The formatting of the magnitude <i>m</i> depends upon its value. 1348 * 1349 * <ul> 1350 * 1351 * <li> If the value is NaN or infinite, the literal strings "NaN" or 1352 * "Infinity", respectively, will be output. 1353 * 1354 * <li> If <i>m</i> is zero then it is represented by the string 1355 * {@code "0x0.0p0"}. 1356 * 1357 * <li> If <i>m</i> is a {@code double} value with a normalized 1358 * representation then substrings are used to represent the significand and 1359 * exponent fields. The significand is represented by the characters 1360 * {@code "0x1."} followed by the hexadecimal representation of the rest 1361 * of the significand as a fraction. The exponent is represented by 1362 * {@code 'p'} (<code>'\u0070'</code>) followed by a decimal string of the 1363 * unbiased exponent as if produced by invoking {@link 1364 * Integer#toString(int) Integer.toString} on the exponent value. If the 1365 * precision is specified, the value is rounded to the given number of 1366 * hexadecimal digits. 1367 * 1368 * <li> If <i>m</i> is a {@code double} value with a subnormal 1369 * representation then, unless the precision is specified to be in the range 1370 * 1 through 12, inclusive, the significand is represented by the characters 1371 * {@code '0x0.'} followed by the hexadecimal representation of the rest of 1372 * the significand as a fraction, and the exponent represented by 1373 * {@code 'p-1022'}. If the precision is in the interval 1374 * [1, 12], the subnormal value is normalized such that it 1375 * begins with the characters {@code '0x1.'}, rounded to the number of 1376 * hexadecimal digits of precision, and the exponent adjusted 1377 * accordingly. Note that there must be at least one nonzero digit in a 1378 * subnormal significand. 1379 * 1380 * </ul> 1381 * 1382 * <p> If the {@code '('} or {@code ','} flags are given, then a {@link 1383 * FormatFlagsConversionMismatchException} will be thrown. 1384 * 1385 * <tr><th scope="row" style="vertical-align:top"> {@code 'A'} 1386 * <td style="vertical-align:top"> <code>'\u0041'</code> 1387 * <td> The upper-case variant of {@code 'a'}. The entire string 1388 * representing the number will be converted to upper case including the 1389 * {@code 'x'} (<code>'\u0078'</code>) and {@code 'p'} 1390 * (<code>'\u0070'</code> and all hexadecimal digits {@code 'a'} - 1391 * {@code 'f'} (<code>'\u0061'</code> - <code>'\u0066'</code>). 1392 * 1393 * </tbody> 1394 * </table> 1395 * 1396 * <p> All <a href="#intFlags">flags</a> defined for Byte, Short, Integer, and 1397 * Long apply. 1398 * 1399 * <p> If the {@code '#'} flag is given, then the decimal separator will 1400 * always be present. 1401 * 1402 * <p> If no <a id="floatdFlags">flags</a> are given the default formatting 1403 * is as follows: 1404 * 1405 * <ul> 1406 * 1407 * <li> The output is right-justified within the {@code width} 1408 * 1409 * <li> Negative numbers begin with a {@code '-'} 1410 * 1411 * <li> Positive numbers and positive zero do not include a sign or extra 1412 * leading space 1413 * 1414 * <li> No grouping separators are included 1415 * 1416 * <li> The decimal separator will only appear if a digit follows it 1417 * 1418 * </ul> 1419 * 1420 * <p> The <a id="floatDWidth">width</a> is the minimum number of characters 1421 * to be written to the output. This includes any signs, digits, grouping 1422 * separators, decimal separators, exponential symbol, radix indicator, 1423 * parentheses, and strings representing infinity and NaN as applicable. If 1424 * the length of the converted value is less than the width then the output 1425 * will be padded by spaces (<code>'\u0020'</code>) until the total number of 1426 * characters equals width. The padding is on the left by default. If the 1427 * {@code '-'} flag is given then the padding will be on the right. If width 1428 * is not specified then there is no minimum. 1429 * 1430 * <p> If the <a id="floatDPrec">conversion</a> is {@code 'e'}, 1431 * {@code 'E'} or {@code 'f'}, then the precision is the number of digits 1432 * after the decimal separator. If the precision is not specified, then it is 1433 * assumed to be {@code 6}. 1434 * 1435 * <p> If the conversion is {@code 'g'} or {@code 'G'}, then the precision is 1436 * the total number of significant digits in the resulting magnitude after 1437 * rounding. If the precision is not specified, then the default value is 1438 * {@code 6}. If the precision is {@code 0}, then it is taken to be 1439 * {@code 1}. 1440 * 1441 * <p> If the conversion is {@code 'a'} or {@code 'A'}, then the precision 1442 * is the number of hexadecimal digits after the radix point. If the 1443 * precision is not provided, then all of the digits as returned by {@link 1444 * Double#toHexString(double)} will be output. 1445 * 1446 * <p><a id="dnbdec"><b> BigDecimal </b></a> 1447 * 1448 * <p> The following conversions may be applied {@link java.math.BigDecimal 1449 * BigDecimal}. 1450 * 1451 * <table class="striped"> 1452 * <caption style="display:none">floatConv</caption> 1453 * <tbody> 1454 * 1455 * <tr><th scope="row" style="vertical-align:top"> {@code 'e'} 1456 * <td style="vertical-align:top"> <code>'\u0065'</code> 1457 * <td> Requires the output to be formatted using <a 1458 * id="bscientific">computerized scientific notation</a>. The <a 1459 * href="#L10nAlgorithm">localization algorithm</a> is applied. 1460 * 1461 * <p> The formatting of the magnitude <i>m</i> depends upon its value. 1462 * 1463 * <p> If <i>m</i> is positive-zero or negative-zero, then the exponent 1464 * will be {@code "+00"}. 1465 * 1466 * <p> Otherwise, the result is a string that represents the sign and 1467 * magnitude (absolute value) of the argument. The formatting of the sign 1468 * is described in the <a href="#L10nAlgorithm">localization 1469 * algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its 1470 * value. 1471 * 1472 * <p> Let <i>n</i> be the unique integer such that 10<sup><i>n</i></sup> 1473 * <= <i>m</i> < 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the 1474 * mathematically exact quotient of <i>m</i> and 10<sup><i>n</i></sup> so 1475 * that 1 <= <i>a</i> < 10. The magnitude is then represented as the 1476 * integer part of <i>a</i>, as a single decimal digit, followed by the 1477 * decimal separator followed by decimal digits representing the fractional 1478 * part of <i>a</i>, followed by the exponent symbol {@code 'e'} 1479 * (<code>'\u0065'</code>), followed by the sign of the exponent, followed 1480 * by a representation of <i>n</i> as a decimal integer, as produced by the 1481 * method {@link Long#toString(long, int)}, and zero-padded to include at 1482 * least two digits. 1483 * 1484 * <p> The number of digits in the result for the fractional part of 1485 * <i>m</i> or <i>a</i> is equal to the precision. If the precision is not 1486 * specified then the default value is {@code 6}. If the precision is 1487 * less than the number of digits to the right of the decimal point then 1488 * the value will be rounded using the 1489 * {@linkplain java.math.RoundingMode#HALF_UP round half up 1490 * algorithm}. Otherwise, zeros may be appended to reach the precision. 1491 * For a canonical representation of the value, use {@link 1492 * BigDecimal#toString()}. 1493 * 1494 * <p> If the {@code ','} flag is given, then an {@link 1495 * FormatFlagsConversionMismatchException} will be thrown. 1496 * 1497 * <tr><th scope="row" style="vertical-align:top"> {@code 'E'} 1498 * <td style="vertical-align:top"> <code>'\u0045'</code> 1499 * <td> The upper-case variant of {@code 'e'}. The exponent symbol 1500 * will be {@code 'E'} (<code>'\u0045'</code>). 1501 * 1502 * <tr><th scope="row" style="vertical-align:top"> {@code 'g'} 1503 * <td style="vertical-align:top"> <code>'\u0067'</code> 1504 * <td> Requires the output to be formatted in general scientific notation 1505 * as described below. The <a href="#L10nAlgorithm">localization 1506 * algorithm</a> is applied. 1507 * 1508 * <p> After rounding for the precision, the formatting of the resulting 1509 * magnitude <i>m</i> depends on its value. 1510 * 1511 * <p> If <i>m</i> is greater than or equal to 10<sup>-4</sup> but less 1512 * than 10<sup>precision</sup> then it is represented in <i><a 1513 * href="#bdecimal">decimal format</a></i>. 1514 * 1515 * <p> If <i>m</i> is less than 10<sup>-4</sup> or greater than or equal to 1516 * 10<sup>precision</sup>, then it is represented in <i><a 1517 * href="#bscientific">computerized scientific notation</a></i>. 1518 * 1519 * <p> The total number of significant digits in <i>m</i> is equal to the 1520 * precision. If the precision is not specified, then the default value is 1521 * {@code 6}. If the precision is {@code 0}, then it is taken to be 1522 * {@code 1}. 1523 * 1524 * <p> If the {@code '#'} flag is given then an {@link 1525 * FormatFlagsConversionMismatchException} will be thrown. 1526 * 1527 * <tr><th scope="row" style="vertical-align:top"> {@code 'G'} 1528 * <td style="vertical-align:top"> <code>'\u0047'</code> 1529 * <td> The upper-case variant of {@code 'g'}. 1530 * 1531 * <tr><th scope="row" style="vertical-align:top"> {@code 'f'} 1532 * <td style="vertical-align:top"> <code>'\u0066'</code> 1533 * <td> Requires the output to be formatted using <a id="bdecimal">decimal 1534 * format</a>. The <a href="#L10nAlgorithm">localization algorithm</a> is 1535 * applied. 1536 * 1537 * <p> The result is a string that represents the sign and magnitude 1538 * (absolute value) of the argument. The formatting of the sign is 1539 * described in the <a href="#L10nAlgorithm">localization 1540 * algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its 1541 * value. 1542 * 1543 * <p> The magnitude is formatted as the integer part of <i>m</i>, with no 1544 * leading zeroes, followed by the decimal separator followed by one or 1545 * more decimal digits representing the fractional part of <i>m</i>. 1546 * 1547 * <p> The number of digits in the result for the fractional part of 1548 * <i>m</i> or <i>a</i> is equal to the precision. If the precision is not 1549 * specified then the default value is {@code 6}. If the precision is 1550 * less than the number of digits to the right of the decimal point 1551 * then the value will be rounded using the 1552 * {@linkplain java.math.RoundingMode#HALF_UP round half up 1553 * algorithm}. Otherwise, zeros may be appended to reach the precision. 1554 * For a canonical representation of the value, use {@link 1555 * BigDecimal#toString()}. 1556 * 1557 * </tbody> 1558 * </table> 1559 * 1560 * <p> All <a href="#intFlags">flags</a> defined for Byte, Short, Integer, and 1561 * Long apply. 1562 * 1563 * <p> If the {@code '#'} flag is given, then the decimal separator will 1564 * always be present. 1565 * 1566 * <p> The <a href="#floatdFlags">default behavior</a> when no flags are 1567 * given is the same as for Float and Double. 1568 * 1569 * <p> The specification of <a href="#floatDWidth">width</a> and <a 1570 * href="#floatDPrec">precision</a> is the same as defined for Float and 1571 * Double. 1572 * 1573 * <h3><a id="ddt">Date/Time</a></h3> 1574 * 1575 * <p> This conversion may be applied to {@code long}, {@link Long}, {@link 1576 * Calendar}, {@link Date} and {@link TemporalAccessor TemporalAccessor} 1577 * 1578 * <table class="striped"> 1579 * <caption style="display:none">DTConv</caption> 1580 * <tbody> 1581 * 1582 * <tr><th scope="row" style="vertical-align:top"> {@code 't'} 1583 * <td style="vertical-align:top"> <code>'\u0074'</code> 1584 * <td> Prefix for date and time conversion characters. 1585 * <tr><th scope="row" style="vertical-align:top"> {@code 'T'} 1586 * <td style="vertical-align:top"> <code>'\u0054'</code> 1587 * <td> The upper-case variant of {@code 't'}. 1588 * 1589 * </tbody> 1590 * </table> 1591 * 1592 * <p> The following date and time conversion character suffixes are defined 1593 * for the {@code 't'} and {@code 'T'} conversions. The types are similar to 1594 * but not completely identical to those defined by GNU {@code date} and 1595 * POSIX {@code strftime(3c)}. Additional conversion types are provided to 1596 * access Java-specific functionality (e.g. {@code 'L'} for milliseconds 1597 * within the second). 1598 * 1599 * <p> The following conversion characters are used for formatting times: 1600 * 1601 * <table class="striped"> 1602 * <caption style="display:none">time</caption> 1603 * <tbody> 1604 * 1605 * <tr><th scope="row" style="vertical-align:top"> {@code 'H'} 1606 * <td style="vertical-align:top"> <code>'\u0048'</code> 1607 * <td> Hour of the day for the 24-hour clock, formatted as two digits with 1608 * a leading zero as necessary i.e. {@code 00 - 23}. {@code 00} 1609 * corresponds to midnight. 1610 * 1611 * <tr><th scope="row" style="vertical-align:top">{@code 'I'} 1612 * <td style="vertical-align:top"> <code>'\u0049'</code> 1613 * <td> Hour for the 12-hour clock, formatted as two digits with a leading 1614 * zero as necessary, i.e. {@code 01 - 12}. {@code 01} corresponds to 1615 * one o'clock (either morning or afternoon). 1616 * 1617 * <tr><th scope="row" style="vertical-align:top">{@code 'k'} 1618 * <td style="vertical-align:top"> <code>'\u006b'</code> 1619 * <td> Hour of the day for the 24-hour clock, i.e. {@code 0 - 23}. 1620 * {@code 0} corresponds to midnight. 1621 * 1622 * <tr><th scope="row" style="vertical-align:top">{@code 'l'} 1623 * <td style="vertical-align:top"> <code>'\u006c'</code> 1624 * <td> Hour for the 12-hour clock, i.e. {@code 1 - 12}. {@code 1} 1625 * corresponds to one o'clock (either morning or afternoon). 1626 * 1627 * <tr><th scope="row" style="vertical-align:top">{@code 'M'} 1628 * <td style="vertical-align:top"> <code>'\u004d'</code> 1629 * <td> Minute within the hour formatted as two digits with a leading zero 1630 * as necessary, i.e. {@code 00 - 59}. 1631 * 1632 * <tr><th scope="row" style="vertical-align:top">{@code 'S'} 1633 * <td style="vertical-align:top"> <code>'\u0053'</code> 1634 * <td> Seconds within the minute, formatted as two digits with a leading 1635 * zero as necessary, i.e. {@code 00 - 60} ("{@code 60}" is a special 1636 * value required to support leap seconds). 1637 * 1638 * <tr><th scope="row" style="vertical-align:top">{@code 'L'} 1639 * <td style="vertical-align:top"> <code>'\u004c'</code> 1640 * <td> Millisecond within the second formatted as three digits with 1641 * leading zeros as necessary, i.e. {@code 000 - 999}. 1642 * 1643 * <tr><th scope="row" style="vertical-align:top">{@code 'N'} 1644 * <td style="vertical-align:top"> <code>'\u004e'</code> 1645 * <td> Nanosecond within the second, formatted as nine digits with leading 1646 * zeros as necessary, i.e. {@code 000000000 - 999999999}. The precision 1647 * of this value is limited by the resolution of the underlying operating 1648 * system or hardware. 1649 * 1650 * <tr><th scope="row" style="vertical-align:top">{@code 'p'} 1651 * <td style="vertical-align:top"> <code>'\u0070'</code> 1652 * <td> Locale-specific {@linkplain 1653 * java.text.DateFormatSymbols#getAmPmStrings morning or afternoon} marker 1654 * in lower case, e.g."{@code am}" or "{@code pm}". Use of the 1655 * conversion prefix {@code 'T'} forces this output to upper case. (Note 1656 * that {@code 'p'} produces lower-case output. This is different from 1657 * GNU {@code date} and POSIX {@code strftime(3c)} which produce 1658 * upper-case output.) 1659 * 1660 * <tr><th scope="row" style="vertical-align:top">{@code 'z'} 1661 * <td style="vertical-align:top"> <code>'\u007a'</code> 1662 * <td> <a href="http://www.ietf.org/rfc/rfc0822.txt">RFC 822</a> 1663 * style numeric time zone offset from GMT, e.g. {@code -0800}. This 1664 * value will be adjusted as necessary for Daylight Saving Time. For 1665 * {@code long}, {@link Long}, and {@link Date} the time zone used is 1666 * the {@linkplain TimeZone#getDefault() default time zone} for this 1667 * instance of the Java virtual machine. 1668 * 1669 * <tr><th scope="row" style="vertical-align:top">{@code 'Z'} 1670 * <td style="vertical-align:top"> <code>'\u005a'</code> 1671 * <td> A string representing the abbreviation for the time zone. This 1672 * value will be adjusted as necessary for Daylight Saving Time. For 1673 * {@code long}, {@link Long}, and {@link Date} the time zone used is 1674 * the {@linkplain TimeZone#getDefault() default time zone} for this 1675 * instance of the Java virtual machine. The Formatter's locale will 1676 * supersede the locale of the argument (if any). 1677 * 1678 * <tr><th scope="row" style="vertical-align:top">{@code 's'} 1679 * <td style="vertical-align:top"> <code>'\u0073'</code> 1680 * <td> Seconds since the beginning of the epoch starting at 1 January 1970 1681 * {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE/1000} to 1682 * {@code Long.MAX_VALUE/1000}. 1683 * 1684 * <tr><th scope="row" style="vertical-align:top">{@code 'Q'} 1685 * <td style="vertical-align:top"> <code>'\u004f'</code> 1686 * <td> Milliseconds since the beginning of the epoch starting at 1 January 1687 * 1970 {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE} to 1688 * {@code Long.MAX_VALUE}. The precision of this value is limited by 1689 * the resolution of the underlying operating system or hardware. 1690 * 1691 * </tbody> 1692 * </table> 1693 * 1694 * <p> The following conversion characters are used for formatting dates: 1695 * 1696 * <table class="striped"> 1697 * <caption style="display:none">date</caption> 1698 * <tbody> 1699 * 1700 * <tr><th scope="row" style="vertical-align:top">{@code 'B'} 1701 * <td style="vertical-align:top"> <code>'\u0042'</code> 1702 * <td> Locale-specific {@linkplain java.text.DateFormatSymbols#getMonths 1703 * full month name}, e.g. {@code "January"}, {@code "February"}. 1704 * 1705 * <tr><th scope="row" style="vertical-align:top">{@code 'b'} 1706 * <td style="vertical-align:top"> <code>'\u0062'</code> 1707 * <td> Locale-specific {@linkplain 1708 * java.text.DateFormatSymbols#getShortMonths abbreviated month name}, 1709 * e.g. {@code "Jan"}, {@code "Feb"}. 1710 * 1711 * <tr><th scope="row" style="vertical-align:top">{@code 'h'} 1712 * <td style="vertical-align:top"> <code>'\u0068'</code> 1713 * <td> Same as {@code 'b'}. 1714 * 1715 * <tr><th scope="row" style="vertical-align:top">{@code 'A'} 1716 * <td style="vertical-align:top"> <code>'\u0041'</code> 1717 * <td> Locale-specific full name of the {@linkplain 1718 * java.text.DateFormatSymbols#getWeekdays day of the week}, 1719 * e.g. {@code "Sunday"}, {@code "Monday"} 1720 * 1721 * <tr><th scope="row" style="vertical-align:top">{@code 'a'} 1722 * <td style="vertical-align:top"> <code>'\u0061'</code> 1723 * <td> Locale-specific short name of the {@linkplain 1724 * java.text.DateFormatSymbols#getShortWeekdays day of the week}, 1725 * e.g. {@code "Sun"}, {@code "Mon"} 1726 * 1727 * <tr><th scope="row" style="vertical-align:top">{@code 'C'} 1728 * <td style="vertical-align:top"> <code>'\u0043'</code> 1729 * <td> Four-digit year divided by {@code 100}, formatted as two digits 1730 * with leading zero as necessary, i.e. {@code 00 - 99} 1731 * 1732 * <tr><th scope="row" style="vertical-align:top">{@code 'Y'} 1733 * <td style="vertical-align:top"> <code>'\u0059'</code> <td> Year, formatted to at least 1734 * four digits with leading zeros as necessary, e.g. {@code 0092} equals 1735 * {@code 92} CE for the Gregorian calendar. 1736 * 1737 * <tr><th scope="row" style="vertical-align:top">{@code 'y'} 1738 * <td style="vertical-align:top"> <code>'\u0079'</code> 1739 * <td> Last two digits of the year, formatted with leading zeros as 1740 * necessary, i.e. {@code 00 - 99}. 1741 * 1742 * <tr><th scope="row" style="vertical-align:top">{@code 'j'} 1743 * <td style="vertical-align:top"> <code>'\u006a'</code> 1744 * <td> Day of year, formatted as three digits with leading zeros as 1745 * necessary, e.g. {@code 001 - 366} for the Gregorian calendar. 1746 * {@code 001} corresponds to the first day of the year. 1747 * 1748 * <tr><th scope="row" style="vertical-align:top">{@code 'm'} 1749 * <td style="vertical-align:top"> <code>'\u006d'</code> 1750 * <td> Month, formatted as two digits with leading zeros as necessary, 1751 * i.e. {@code 01 - 13}, where "{@code 01}" is the first month of the 1752 * year and ("{@code 13}" is a special value required to support lunar 1753 * calendars). 1754 * 1755 * <tr><th scope="row" style="vertical-align:top">{@code 'd'} 1756 * <td style="vertical-align:top"> <code>'\u0064'</code> 1757 * <td> Day of month, formatted as two digits with leading zeros as 1758 * necessary, i.e. {@code 01 - 31}, where "{@code 01}" is the first day 1759 * of the month. 1760 * 1761 * <tr><th scope="row" style="vertical-align:top">{@code 'e'} 1762 * <td style="vertical-align:top"> <code>'\u0065'</code> 1763 * <td> Day of month, formatted as two digits, i.e. {@code 1 - 31} where 1764 * "{@code 1}" is the first day of the month. 1765 * 1766 * </tbody> 1767 * </table> 1768 * 1769 * <p> The following conversion characters are used for formatting common 1770 * date/time compositions. 1771 * 1772 * <table class="striped"> 1773 * <caption style="display:none">composites</caption> 1774 * <tbody> 1775 * 1776 * <tr><th scope="row" style="vertical-align:top">{@code 'R'} 1777 * <td style="vertical-align:top"> <code>'\u0052'</code> 1778 * <td> Time formatted for the 24-hour clock as {@code "%tH:%tM"} 1779 * 1780 * <tr><th scope="row" style="vertical-align:top">{@code 'T'} 1781 * <td style="vertical-align:top"> <code>'\u0054'</code> 1782 * <td> Time formatted for the 24-hour clock as {@code "%tH:%tM:%tS"}. 1783 * 1784 * <tr><th scope="row" style="vertical-align:top">{@code 'r'} 1785 * <td style="vertical-align:top"> <code>'\u0072'</code> 1786 * <td> Time formatted for the 12-hour clock as {@code "%tI:%tM:%tS 1787 * %Tp"}. The location of the morning or afternoon marker 1788 * ({@code '%Tp'}) may be locale-dependent. 1789 * 1790 * <tr><th scope="row" style="vertical-align:top">{@code 'D'} 1791 * <td style="vertical-align:top"> <code>'\u0044'</code> 1792 * <td> Date formatted as {@code "%tm/%td/%ty"}. 1793 * 1794 * <tr><th scope="row" style="vertical-align:top">{@code 'F'} 1795 * <td style="vertical-align:top"> <code>'\u0046'</code> 1796 * <td> <a href="http://www.w3.org/TR/NOTE-datetime">ISO 8601</a> 1797 * complete date formatted as {@code "%tY-%tm-%td"}. 1798 * 1799 * <tr><th scope="row" style="vertical-align:top">{@code 'c'} 1800 * <td style="vertical-align:top"> <code>'\u0063'</code> 1801 * <td> Date and time formatted as {@code "%ta %tb %td %tT %tZ %tY"}, 1802 * e.g. {@code "Sun Jul 20 16:17:00 EDT 1969"}. 1803 * 1804 * </tbody> 1805 * </table> 1806 * 1807 * <p> The {@code '-'} flag defined for <a href="#dFlags">General 1808 * conversions</a> applies. If the {@code '#'} flag is given, then a {@link 1809 * FormatFlagsConversionMismatchException} will be thrown. 1810 * 1811 * <p> The width is the minimum number of characters to 1812 * be written to the output. If the length of the converted value is less than 1813 * the {@code width} then the output will be padded by spaces 1814 * (<code>'\u0020'</code>) until the total number of characters equals width. 1815 * The padding is on the left by default. If the {@code '-'} flag is given 1816 * then the padding will be on the right. If width is not specified then there 1817 * is no minimum. 1818 * 1819 * <p> The precision is not applicable. If the precision is specified then an 1820 * {@link IllegalFormatPrecisionException} will be thrown. 1821 * 1822 * <h3><a id="dper">Percent</a></h3> 1823 * 1824 * <p> The conversion does not correspond to any argument. 1825 * 1826 * <table class="striped"> 1827 * <caption style="display:none">DTConv</caption> 1828 * <tbody> 1829 * 1830 * <tr><th scope="row" style="vertical-align:top">{@code '%'} 1831 * <td> The result is a literal {@code '%'} (<code>'\u0025'</code>) 1832 * 1833 * <p> The width is the minimum number of characters to 1834 * be written to the output including the {@code '%'}. If the length of the 1835 * converted value is less than the {@code width} then the output will be 1836 * padded by spaces (<code>'\u0020'</code>) until the total number of 1837 * characters equals width. The padding is on the left. If width is not 1838 * specified then just the {@code '%'} is output. 1839 * 1840 * <p> The {@code '-'} flag defined for <a href="#dFlags">General 1841 * conversions</a> applies. If any other flags are provided, then a 1842 * {@link IllegalFormatFlagsException } will be thrown. 1843 * 1844 * <p> The precision is not applicable. If the precision is specified an 1845 * {@link IllegalFormatPrecisionException} will be thrown. 1846 * 1847 * </tbody> 1848 * </table> 1849 * 1850 * <h3><a id="dls">Line Separator</a></h3> 1851 * 1852 * <p> The conversion does not correspond to any argument. 1853 * 1854 * <table class="striped"> 1855 * <caption style="display:none">DTConv</caption> 1856 * <tbody> 1857 * 1858 * <tr><th scope="row" style="vertical-align:top">{@code 'n'} 1859 * <td> the platform-specific line separator as returned by {@link 1860 * System#lineSeparator()}. 1861 * 1862 * </tbody> 1863 * </table> 1864 * 1865 * <p> Flags, width, and precision are not applicable. If any are provided an 1866 * {@link IllegalFormatFlagsException}, {@link IllegalFormatWidthException}, 1867 * and {@link IllegalFormatPrecisionException}, respectively will be thrown. 1868 * 1869 * <h3><a id="dpos">Argument Index</a></h3> 1870 * 1871 * <p> Format specifiers can reference arguments in three ways: 1872 * 1873 * <ul> 1874 * 1875 * <li> <i>Explicit indexing</i> is used when the format specifier contains an 1876 * argument index. The argument index is a decimal integer indicating the 1877 * position of the argument in the argument list. The first argument is 1878 * referenced by "{@code 1$}", the second by "{@code 2$}", etc. An argument 1879 * may be referenced more than once. 1880 * 1881 * <p> For example: 1882 * 1883 * <blockquote><pre> 1884 * formatter.format("%4$s %3$s %2$s %1$s %4$s %3$s %2$s %1$s", 1885 * "a", "b", "c", "d") 1886 * // -> "d c b a d c b a" 1887 * </pre></blockquote> 1888 * 1889 * <li> <i>Relative indexing</i> is used when the format specifier contains a 1890 * {@code '<'} (<code>'\u003c'</code>) flag which causes the argument for 1891 * the previous format specifier to be re-used. If there is no previous 1892 * argument, then a {@link MissingFormatArgumentException} is thrown. 1893 * 1894 * <blockquote><pre> 1895 * formatter.format("%s %s %<s %<s", "a", "b", "c", "d") 1896 * // -> "a b b b" 1897 * // "c" and "d" are ignored because they are not referenced 1898 * </pre></blockquote> 1899 * 1900 * <li> <i>Ordinary indexing</i> is used when the format specifier contains 1901 * neither an argument index nor a {@code '<'} flag. Each format specifier 1902 * which uses ordinary indexing is assigned a sequential implicit index into 1903 * argument list which is independent of the indices used by explicit or 1904 * relative indexing. 1905 * 1906 * <blockquote><pre> 1907 * formatter.format("%s %s %s %s", "a", "b", "c", "d") 1908 * // -> "a b c d" 1909 * </pre></blockquote> 1910 * 1911 * </ul> 1912 * 1913 * <p> It is possible to have a format string which uses all forms of indexing, 1914 * for example: 1915 * 1916 * <blockquote><pre> 1917 * formatter.format("%2$s %s %<s %s", "a", "b", "c", "d") 1918 * // -> "b a a b" 1919 * // "c" and "d" are ignored because they are not referenced 1920 * </pre></blockquote> 1921 * 1922 * <p> The maximum number of arguments is limited by the maximum dimension of a 1923 * Java array as defined by 1924 * <cite>The Java Virtual Machine Specification</cite>. 1925 * If the argument index does not correspond to an 1926 * available argument, then a {@link MissingFormatArgumentException} is thrown. 1927 * 1928 * <p> If there are more arguments than format specifiers, the extra arguments 1929 * are ignored. 1930 * 1931 * <p> Unless otherwise specified, passing a {@code null} argument to any 1932 * method or constructor in this class will cause a {@link 1933 * NullPointerException} to be thrown. 1934 * 1935 * @author Iris Clark 1936 * @since 1.5 1937 */ 1938 // Android-added: errorprone crashes with NPE otherwise. See: https://github.com/google/error-prone/issues/2638 1939 @SuppressWarnings("FallThrough") 1940 public final class Formatter implements Closeable, Flushable { 1941 private Appendable a; 1942 private final Locale l; 1943 1944 private IOException lastException; 1945 1946 // Non-character value used to mark zero as uninitialized 1947 private static final char ZERO_SENTINEL = '\uFFFE'; 1948 private char zero = ZERO_SENTINEL; 1949 1950 /** 1951 * Returns a charset object for the given charset name. 1952 * @throws NullPointerException is csn is null 1953 * @throws UnsupportedEncodingException if the charset is not supported 1954 */ toCharset(String csn)1955 private static Charset toCharset(String csn) 1956 throws UnsupportedEncodingException 1957 { 1958 Objects.requireNonNull(csn, "charsetName"); 1959 try { 1960 return Charset.forName(csn); 1961 } catch (IllegalCharsetNameException|UnsupportedCharsetException unused) { 1962 // UnsupportedEncodingException should be thrown 1963 throw new UnsupportedEncodingException(csn); 1964 } 1965 } 1966 nonNullAppendable(Appendable a)1967 private static final Appendable nonNullAppendable(Appendable a) { 1968 if (a == null) 1969 return new StringBuilder(); 1970 1971 return a; 1972 } 1973 1974 /* Private constructors */ Formatter(Locale l, Appendable a)1975 private Formatter(Locale l, Appendable a) { 1976 this.a = a; 1977 this.l = l; 1978 } 1979 Formatter(Charset charset, Locale l, File file)1980 private Formatter(Charset charset, Locale l, File file) 1981 throws FileNotFoundException 1982 { 1983 this(l, 1984 new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charset))); 1985 } 1986 1987 /** 1988 * Constructs a new formatter. 1989 * 1990 * <p> The destination of the formatted output is a {@link StringBuilder} 1991 * which may be retrieved by invoking {@link #out out()} and whose 1992 * current content may be converted into a string by invoking {@link 1993 * #toString toString()}. The locale used is the {@linkplain 1994 * Locale#getDefault(Locale.Category) default locale} for 1995 * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java 1996 * virtual machine. 1997 */ Formatter()1998 public Formatter() { 1999 this(Locale.getDefault(Locale.Category.FORMAT), new StringBuilder()); 2000 } 2001 2002 /** 2003 * Constructs a new formatter with the specified destination. 2004 * 2005 * <p> The locale used is the {@linkplain 2006 * Locale#getDefault(Locale.Category) default locale} for 2007 * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java 2008 * virtual machine. 2009 * 2010 * @param a 2011 * Destination for the formatted output. If {@code a} is 2012 * {@code null} then a {@link StringBuilder} will be created. 2013 */ Formatter(Appendable a)2014 public Formatter(Appendable a) { 2015 this(Locale.getDefault(Locale.Category.FORMAT), nonNullAppendable(a)); 2016 } 2017 2018 /** 2019 * Constructs a new formatter with the specified locale. 2020 * 2021 * <p> The destination of the formatted output is a {@link StringBuilder} 2022 * which may be retrieved by invoking {@link #out out()} and whose current 2023 * content may be converted into a string by invoking {@link #toString 2024 * toString()}. 2025 * 2026 * @param l 2027 * The {@linkplain java.util.Locale locale} to apply during 2028 * formatting. If {@code l} is {@code null} then no localization 2029 * is applied. 2030 */ Formatter(Locale l)2031 public Formatter(Locale l) { 2032 this(l, new StringBuilder()); 2033 } 2034 2035 /** 2036 * Constructs a new formatter with the specified destination and locale. 2037 * 2038 * @param a 2039 * Destination for the formatted output. If {@code a} is 2040 * {@code null} then a {@link StringBuilder} will be created. 2041 * 2042 * @param l 2043 * The {@linkplain java.util.Locale locale} to apply during 2044 * formatting. If {@code l} is {@code null} then no localization 2045 * is applied. 2046 */ Formatter(Appendable a, Locale l)2047 public Formatter(Appendable a, Locale l) { 2048 this(l, nonNullAppendable(a)); 2049 } 2050 2051 /** 2052 * Constructs a new formatter with the specified file name. 2053 * 2054 * <p> The charset used is the {@linkplain 2055 * java.nio.charset.Charset#defaultCharset() default charset} for this 2056 * instance of the Java virtual machine. 2057 * 2058 * <p> The locale used is the {@linkplain 2059 * Locale#getDefault(Locale.Category) default locale} for 2060 * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java 2061 * virtual machine. 2062 * 2063 * @param fileName 2064 * The name of the file to use as the destination of this 2065 * formatter. If the file exists then it will be truncated to 2066 * zero size; otherwise, a new file will be created. The output 2067 * will be written to the file and is buffered. 2068 * 2069 * @throws SecurityException 2070 * If a security manager is present and {@link 2071 * SecurityManager#checkWrite checkWrite(fileName)} denies write 2072 * access to the file 2073 * 2074 * @throws FileNotFoundException 2075 * If the given file name does not denote an existing, writable 2076 * regular file and a new regular file of that name cannot be 2077 * created, or if some other error occurs while opening or 2078 * creating the file 2079 */ Formatter(String fileName)2080 public Formatter(String fileName) throws FileNotFoundException { 2081 this(Locale.getDefault(Locale.Category.FORMAT), 2082 new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName)))); 2083 } 2084 2085 /** 2086 * Constructs a new formatter with the specified file name and charset. 2087 * 2088 * <p> The locale used is the {@linkplain 2089 * Locale#getDefault(Locale.Category) default locale} for 2090 * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java 2091 * virtual machine. 2092 * 2093 * @param fileName 2094 * The name of the file to use as the destination of this 2095 * formatter. If the file exists then it will be truncated to 2096 * zero size; otherwise, a new file will be created. The output 2097 * will be written to the file and is buffered. 2098 * 2099 * @param csn 2100 * The name of a supported {@linkplain java.nio.charset.Charset 2101 * charset} 2102 * 2103 * @throws FileNotFoundException 2104 * If the given file name does not denote an existing, writable 2105 * regular file and a new regular file of that name cannot be 2106 * created, or if some other error occurs while opening or 2107 * creating the file 2108 * 2109 * @throws SecurityException 2110 * If a security manager is present and {@link 2111 * SecurityManager#checkWrite checkWrite(fileName)} denies write 2112 * access to the file 2113 * 2114 * @throws UnsupportedEncodingException 2115 * If the named charset is not supported 2116 */ Formatter(String fileName, String csn)2117 public Formatter(String fileName, String csn) 2118 throws FileNotFoundException, UnsupportedEncodingException 2119 { 2120 this(fileName, csn, Locale.getDefault(Locale.Category.FORMAT)); 2121 } 2122 2123 /** 2124 * Constructs a new formatter with the specified file name, charset, and 2125 * locale. 2126 * 2127 * @param fileName 2128 * The name of the file to use as the destination of this 2129 * formatter. If the file exists then it will be truncated to 2130 * zero size; otherwise, a new file will be created. The output 2131 * will be written to the file and is buffered. 2132 * 2133 * @param csn 2134 * The name of a supported {@linkplain java.nio.charset.Charset 2135 * charset} 2136 * 2137 * @param l 2138 * The {@linkplain java.util.Locale locale} to apply during 2139 * formatting. If {@code l} is {@code null} then no localization 2140 * is applied. 2141 * 2142 * @throws FileNotFoundException 2143 * If the given file name does not denote an existing, writable 2144 * regular file and a new regular file of that name cannot be 2145 * created, or if some other error occurs while opening or 2146 * creating the file 2147 * 2148 * @throws SecurityException 2149 * If a security manager is present and {@link 2150 * SecurityManager#checkWrite checkWrite(fileName)} denies write 2151 * access to the file 2152 * 2153 * @throws UnsupportedEncodingException 2154 * If the named charset is not supported 2155 */ Formatter(String fileName, String csn, Locale l)2156 public Formatter(String fileName, String csn, Locale l) 2157 throws FileNotFoundException, UnsupportedEncodingException 2158 { 2159 this(toCharset(csn), l, new File(fileName)); 2160 } 2161 2162 /** 2163 * Constructs a new formatter with the specified file name, charset, and 2164 * locale. 2165 * 2166 * @param fileName 2167 * The name of the file to use as the destination of this 2168 * formatter. If the file exists then it will be truncated to 2169 * zero size; otherwise, a new file will be created. The output 2170 * will be written to the file and is buffered. 2171 * 2172 * @param charset 2173 * A {@linkplain java.nio.charset.Charset charset} 2174 * 2175 * @param l 2176 * The {@linkplain java.util.Locale locale} to apply during 2177 * formatting. If {@code l} is {@code null} then no localization 2178 * is applied. 2179 * 2180 * @throws IOException 2181 * if an I/O error occurs while opening or creating the file 2182 * 2183 * @throws SecurityException 2184 * If a security manager is present and {@link 2185 * SecurityManager#checkWrite checkWrite(fileName)} denies write 2186 * access to the file 2187 * 2188 * @throws NullPointerException 2189 * if {@code fileName} or {@code charset} is {@code null}. 2190 */ Formatter(String fileName, Charset charset, Locale l)2191 public Formatter(String fileName, Charset charset, Locale l) throws IOException { 2192 this(Objects.requireNonNull(charset, "charset"), l, new File(fileName)); 2193 } 2194 2195 /** 2196 * Constructs a new formatter with the specified file. 2197 * 2198 * <p> The charset used is the {@linkplain 2199 * java.nio.charset.Charset#defaultCharset() default charset} for this 2200 * instance of the Java virtual machine. 2201 * 2202 * <p> The locale used is the {@linkplain 2203 * Locale#getDefault(Locale.Category) default locale} for 2204 * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java 2205 * virtual machine. 2206 * 2207 * @param file 2208 * The file to use as the destination of this formatter. If the 2209 * file exists then it will be truncated to zero size; otherwise, 2210 * a new file will be created. The output will be written to the 2211 * file and is buffered. 2212 * 2213 * @throws SecurityException 2214 * If a security manager is present and {@link 2215 * SecurityManager#checkWrite checkWrite(file.getPath())} denies 2216 * write access to the file 2217 * 2218 * @throws FileNotFoundException 2219 * If the given file object does not denote an existing, writable 2220 * regular file and a new regular file of that name cannot be 2221 * created, or if some other error occurs while opening or 2222 * creating the file 2223 */ Formatter(File file)2224 public Formatter(File file) throws FileNotFoundException { 2225 this(Locale.getDefault(Locale.Category.FORMAT), 2226 new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)))); 2227 } 2228 2229 /** 2230 * Constructs a new formatter with the specified file and charset. 2231 * 2232 * <p> The locale used is the {@linkplain 2233 * Locale#getDefault(Locale.Category) default locale} for 2234 * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java 2235 * virtual machine. 2236 * 2237 * @param file 2238 * The file to use as the destination of this formatter. If the 2239 * file exists then it will be truncated to zero size; otherwise, 2240 * a new file will be created. The output will be written to the 2241 * file and is buffered. 2242 * 2243 * @param csn 2244 * The name of a supported {@linkplain java.nio.charset.Charset 2245 * charset} 2246 * 2247 * @throws FileNotFoundException 2248 * If the given file object does not denote an existing, writable 2249 * regular file and a new regular file of that name cannot be 2250 * created, or if some other error occurs while opening or 2251 * creating the file 2252 * 2253 * @throws SecurityException 2254 * If a security manager is present and {@link 2255 * SecurityManager#checkWrite checkWrite(file.getPath())} denies 2256 * write access to the file 2257 * 2258 * @throws UnsupportedEncodingException 2259 * If the named charset is not supported 2260 */ Formatter(File file, String csn)2261 public Formatter(File file, String csn) 2262 throws FileNotFoundException, UnsupportedEncodingException 2263 { 2264 this(file, csn, Locale.getDefault(Locale.Category.FORMAT)); 2265 } 2266 2267 /** 2268 * Constructs a new formatter with the specified file, charset, and 2269 * locale. 2270 * 2271 * @param file 2272 * The file to use as the destination of this formatter. If the 2273 * file exists then it will be truncated to zero size; otherwise, 2274 * a new file will be created. The output will be written to the 2275 * file and is buffered. 2276 * 2277 * @param csn 2278 * The name of a supported {@linkplain java.nio.charset.Charset 2279 * charset} 2280 * 2281 * @param l 2282 * The {@linkplain java.util.Locale locale} to apply during 2283 * formatting. If {@code l} is {@code null} then no localization 2284 * is applied. 2285 * 2286 * @throws FileNotFoundException 2287 * If the given file object does not denote an existing, writable 2288 * regular file and a new regular file of that name cannot be 2289 * created, or if some other error occurs while opening or 2290 * creating the file 2291 * 2292 * @throws SecurityException 2293 * If a security manager is present and {@link 2294 * SecurityManager#checkWrite checkWrite(file.getPath())} denies 2295 * write access to the file 2296 * 2297 * @throws UnsupportedEncodingException 2298 * If the named charset is not supported 2299 */ Formatter(File file, String csn, Locale l)2300 public Formatter(File file, String csn, Locale l) 2301 throws FileNotFoundException, UnsupportedEncodingException 2302 { 2303 this(toCharset(csn), l, file); 2304 } 2305 2306 /** 2307 * Constructs a new formatter with the specified file, charset, and 2308 * locale. 2309 * 2310 * @param file 2311 * The file to use as the destination of this formatter. If the 2312 * file exists then it will be truncated to zero size; otherwise, 2313 * a new file will be created. The output will be written to the 2314 * file and is buffered. 2315 * 2316 * @param charset 2317 * A {@linkplain java.nio.charset.Charset charset} 2318 * 2319 * @param l 2320 * The {@linkplain java.util.Locale locale} to apply during 2321 * formatting. If {@code l} is {@code null} then no localization 2322 * is applied. 2323 * 2324 * @throws IOException 2325 * if an I/O error occurs while opening or creating the file 2326 * 2327 * @throws SecurityException 2328 * If a security manager is present and {@link 2329 * SecurityManager#checkWrite checkWrite(file.getPath())} denies 2330 * write access to the file 2331 * 2332 * @throws NullPointerException 2333 * if {@code file} or {@code charset} is {@code null}. 2334 */ Formatter(File file, Charset charset, Locale l)2335 public Formatter(File file, Charset charset, Locale l) throws IOException { 2336 this(Objects.requireNonNull(charset, "charset"), l, file); 2337 } 2338 2339 2340 /** 2341 * Constructs a new formatter with the specified print stream. 2342 * 2343 * <p> The locale used is the {@linkplain 2344 * Locale#getDefault(Locale.Category) default locale} for 2345 * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java 2346 * virtual machine. 2347 * 2348 * <p> Characters are written to the given {@link java.io.PrintStream 2349 * PrintStream} object and are therefore encoded using that object's 2350 * charset. 2351 * 2352 * @param ps 2353 * The stream to use as the destination of this formatter. 2354 */ Formatter(PrintStream ps)2355 public Formatter(PrintStream ps) { 2356 this(Locale.getDefault(Locale.Category.FORMAT), 2357 (Appendable)Objects.requireNonNull(ps)); 2358 } 2359 2360 /** 2361 * Constructs a new formatter with the specified output stream. 2362 * 2363 * <p> The charset used is the {@linkplain 2364 * java.nio.charset.Charset#defaultCharset() default charset} for this 2365 * instance of the Java virtual machine. 2366 * 2367 * <p> The locale used is the {@linkplain 2368 * Locale#getDefault(Locale.Category) default locale} for 2369 * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java 2370 * virtual machine. 2371 * 2372 * @param os 2373 * The output stream to use as the destination of this formatter. 2374 * The output will be buffered. 2375 */ Formatter(OutputStream os)2376 public Formatter(OutputStream os) { 2377 this(Locale.getDefault(Locale.Category.FORMAT), 2378 new BufferedWriter(new OutputStreamWriter(os))); 2379 } 2380 2381 /** 2382 * Constructs a new formatter with the specified output stream and 2383 * charset. 2384 * 2385 * <p> The locale used is the {@linkplain 2386 * Locale#getDefault(Locale.Category) default locale} for 2387 * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java 2388 * virtual machine. 2389 * 2390 * @param os 2391 * The output stream to use as the destination of this formatter. 2392 * The output will be buffered. 2393 * 2394 * @param csn 2395 * The name of a supported {@linkplain java.nio.charset.Charset 2396 * charset} 2397 * 2398 * @throws UnsupportedEncodingException 2399 * If the named charset is not supported 2400 */ Formatter(OutputStream os, String csn)2401 public Formatter(OutputStream os, String csn) 2402 throws UnsupportedEncodingException 2403 { 2404 this(os, csn, Locale.getDefault(Locale.Category.FORMAT)); 2405 } 2406 2407 /** 2408 * Constructs a new formatter with the specified output stream, charset, 2409 * and locale. 2410 * 2411 * @param os 2412 * The output stream to use as the destination of this formatter. 2413 * The output will be buffered. 2414 * 2415 * @param csn 2416 * The name of a supported {@linkplain java.nio.charset.Charset 2417 * charset} 2418 * 2419 * @param l 2420 * The {@linkplain java.util.Locale locale} to apply during 2421 * formatting. If {@code l} is {@code null} then no localization 2422 * is applied. 2423 * 2424 * @throws UnsupportedEncodingException 2425 * If the named charset is not supported 2426 */ Formatter(OutputStream os, String csn, Locale l)2427 public Formatter(OutputStream os, String csn, Locale l) 2428 throws UnsupportedEncodingException 2429 { 2430 this(l, new BufferedWriter(new OutputStreamWriter(os, csn))); 2431 } 2432 2433 /** 2434 * Constructs a new formatter with the specified output stream, charset, 2435 * and locale. 2436 * 2437 * @param os 2438 * The output stream to use as the destination of this formatter. 2439 * The output will be buffered. 2440 * 2441 * @param charset 2442 * A {@linkplain java.nio.charset.Charset charset} 2443 * 2444 * @param l 2445 * The {@linkplain java.util.Locale locale} to apply during 2446 * formatting. If {@code l} is {@code null} then no localization 2447 * is applied. 2448 * 2449 * @throws NullPointerException 2450 * if {@code os} or {@code charset} is {@code null}. 2451 */ Formatter(OutputStream os, Charset charset, Locale l)2452 public Formatter(OutputStream os, Charset charset, Locale l) { 2453 this(l, new BufferedWriter(new OutputStreamWriter(os, charset))); 2454 } 2455 zero()2456 private char zero() { 2457 char zero = this.zero; 2458 if (zero == ZERO_SENTINEL) { 2459 if ((l != null) && !l.equals(Locale.US)) { 2460 // Android-changed: Improve the performance by 10x http://b/197788756 2461 // Unclear if this mapping is needed but inherited from DecimalFormatSymbols 2462 DecimalFormatData decimalFormatData = 2463 DecimalFormatData.getInstance(LocaleData.mapInvalidAndNullLocales(l)); 2464 return decimalFormatData.getZeroDigit(); 2465 // DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l); 2466 // zero = dfs.getZeroDigit(); 2467 } else { 2468 zero = '0'; 2469 } 2470 this.zero = zero; 2471 } 2472 return zero; 2473 } 2474 2475 /** 2476 * Returns the locale set by the construction of this formatter. 2477 * 2478 * <p> The {@link #format(java.util.Locale,String,Object...) format} method 2479 * for this object which has a locale argument does not change this value. 2480 * 2481 * @return {@code null} if no localization is applied, otherwise a 2482 * locale 2483 * 2484 * @throws FormatterClosedException 2485 * If this formatter has been closed by invoking its {@link 2486 * #close()} method 2487 */ locale()2488 public Locale locale() { 2489 ensureOpen(); 2490 return l; 2491 } 2492 2493 /** 2494 * Returns the destination for the output. 2495 * 2496 * @return The destination for the output 2497 * 2498 * @throws FormatterClosedException 2499 * If this formatter has been closed by invoking its {@link 2500 * #close()} method 2501 */ out()2502 public Appendable out() { 2503 ensureOpen(); 2504 return a; 2505 } 2506 2507 /** 2508 * Returns the result of invoking {@code toString()} on the destination 2509 * for the output. For example, the following code formats text into a 2510 * {@link StringBuilder} then retrieves the resultant string: 2511 * 2512 * <blockquote><pre> 2513 * Formatter f = new Formatter(); 2514 * f.format("Last reboot at %tc", lastRebootDate); 2515 * String s = f.toString(); 2516 * // -> s == "Last reboot at Sat Jan 01 00:00:00 PST 2000" 2517 * </pre></blockquote> 2518 * 2519 * <p> An invocation of this method behaves in exactly the same way as the 2520 * invocation 2521 * 2522 * <pre> 2523 * out().toString() </pre> 2524 * 2525 * <p> Depending on the specification of {@code toString} for the {@link 2526 * Appendable}, the returned string may or may not contain the characters 2527 * written to the destination. For instance, buffers typically return 2528 * their contents in {@code toString()}, but streams cannot since the 2529 * data is discarded. 2530 * 2531 * @return The result of invoking {@code toString()} on the destination 2532 * for the output 2533 * 2534 * @throws FormatterClosedException 2535 * If this formatter has been closed by invoking its {@link 2536 * #close()} method 2537 */ toString()2538 public String toString() { 2539 ensureOpen(); 2540 return a.toString(); 2541 } 2542 2543 /** 2544 * Flushes this formatter. If the destination implements the {@link 2545 * java.io.Flushable} interface, its {@code flush} method will be invoked. 2546 * 2547 * <p> Flushing a formatter writes any buffered output in the destination 2548 * to the underlying stream. 2549 * 2550 * @throws FormatterClosedException 2551 * If this formatter has been closed by invoking its {@link 2552 * #close()} method 2553 */ flush()2554 public void flush() { 2555 ensureOpen(); 2556 if (a instanceof Flushable) { 2557 try { 2558 ((Flushable)a).flush(); 2559 } catch (IOException ioe) { 2560 lastException = ioe; 2561 } 2562 } 2563 } 2564 2565 /** 2566 * Closes this formatter. If the destination implements the {@link 2567 * java.io.Closeable} interface, its {@code close} method will be invoked. 2568 * 2569 * <p> Closing a formatter allows it to release resources it may be holding 2570 * (such as open files). If the formatter is already closed, then invoking 2571 * this method has no effect. 2572 * 2573 * <p> Attempting to invoke any methods except {@link #ioException()} in 2574 * this formatter after it has been closed will result in a {@link 2575 * FormatterClosedException}. 2576 */ close()2577 public void close() { 2578 if (a == null) 2579 return; 2580 try { 2581 if (a instanceof Closeable) 2582 ((Closeable)a).close(); 2583 } catch (IOException ioe) { 2584 lastException = ioe; 2585 } finally { 2586 a = null; 2587 } 2588 } 2589 ensureOpen()2590 private void ensureOpen() { 2591 if (a == null) 2592 throw new FormatterClosedException(); 2593 } 2594 2595 /** 2596 * Returns the {@code IOException} last thrown by this formatter's {@link 2597 * Appendable}. 2598 * 2599 * <p> If the destination's {@code append()} method never throws 2600 * {@code IOException}, then this method will always return {@code null}. 2601 * 2602 * @return The last exception thrown by the Appendable or {@code null} if 2603 * no such exception exists. 2604 */ ioException()2605 public IOException ioException() { 2606 return lastException; 2607 } 2608 2609 /** 2610 * Writes a formatted string to this object's destination using the 2611 * specified format string and arguments. The locale used is the one 2612 * defined during the construction of this formatter. 2613 * 2614 * @param format 2615 * A format string as described in <a href="#syntax">Format string 2616 * syntax</a>. 2617 * 2618 * @param args 2619 * Arguments referenced by the format specifiers in the format 2620 * string. If there are more arguments than format specifiers, the 2621 * extra arguments are ignored. The maximum number of arguments is 2622 * limited by the maximum dimension of a Java array as defined by 2623 * <cite>The Java Virtual Machine Specification</cite>. 2624 * 2625 * @throws IllegalFormatException 2626 * If a format string contains an illegal syntax, a format 2627 * specifier that is incompatible with the given arguments, 2628 * insufficient arguments given the format string, or other 2629 * illegal conditions. For specification of all possible 2630 * formatting errors, see the <a href="#detail">Details</a> 2631 * section of the formatter class specification. 2632 * 2633 * @throws FormatterClosedException 2634 * If this formatter has been closed by invoking its {@link 2635 * #close()} method 2636 * 2637 * @return This formatter 2638 */ format(String format, Object ... args)2639 public Formatter format(String format, Object ... args) { 2640 return format(l, format, args); 2641 } 2642 2643 /** 2644 * Writes a formatted string to this object's destination using the 2645 * specified locale, format string, and arguments. 2646 * 2647 * @param l 2648 * The {@linkplain java.util.Locale locale} to apply during 2649 * formatting. If {@code l} is {@code null} then no localization 2650 * is applied. This does not change this object's locale that was 2651 * set during construction. 2652 * 2653 * @param format 2654 * A format string as described in <a href="#syntax">Format string 2655 * syntax</a> 2656 * 2657 * @param args 2658 * Arguments referenced by the format specifiers in the format 2659 * string. If there are more arguments than format specifiers, the 2660 * extra arguments are ignored. The maximum number of arguments is 2661 * limited by the maximum dimension of a Java array as defined by 2662 * <cite>The Java Virtual Machine Specification</cite>. 2663 * 2664 * @throws IllegalFormatException 2665 * If a format string contains an illegal syntax, a format 2666 * specifier that is incompatible with the given arguments, 2667 * insufficient arguments given the format string, or other 2668 * illegal conditions. For specification of all possible 2669 * formatting errors, see the <a href="#detail">Details</a> 2670 * section of the formatter class specification. 2671 * 2672 * @throws FormatterClosedException 2673 * If this formatter has been closed by invoking its {@link 2674 * #close()} method 2675 * 2676 * @return This formatter 2677 */ format(Locale l, String format, Object ... args)2678 public Formatter format(Locale l, String format, Object ... args) { 2679 ensureOpen(); 2680 2681 // index of last argument referenced 2682 int last = -1; 2683 // last ordinary index 2684 int lasto = -1; 2685 2686 List<FormatString> fsa = parse(format); 2687 for (int i = 0; i < fsa.size(); i++) { 2688 var fs = fsa.get(i); 2689 int index = fs.index(); 2690 try { 2691 switch (index) { 2692 case -2 -> // fixed string, "%n", or "%%" 2693 fs.print(null, l); 2694 case -1 -> { // relative index 2695 if (last < 0 || (args != null && last > args.length - 1)) 2696 throw new MissingFormatArgumentException(fs.toString()); 2697 fs.print((args == null ? null : args[last]), l); 2698 } 2699 case 0 -> { // ordinary index 2700 lasto++; 2701 last = lasto; 2702 if (args != null && lasto > args.length - 1) 2703 throw new MissingFormatArgumentException(fs.toString()); 2704 fs.print((args == null ? null : args[lasto]), l); 2705 } 2706 default -> { // explicit index 2707 last = index - 1; 2708 if (args != null && last > args.length - 1) 2709 throw new MissingFormatArgumentException(fs.toString()); 2710 fs.print((args == null ? null : args[last]), l); 2711 } 2712 } 2713 } catch (IOException x) { 2714 lastException = x; 2715 } 2716 } 2717 return this; 2718 } 2719 2720 // BEGIN Android-changed: changed parse() to manual parsing instead of regex. 2721 /** 2722 * Finds format specifiers in the format string. 2723 */ parse(String s)2724 private List<FormatString> parse(String s) { 2725 ArrayList<FormatString> al = new ArrayList<>(); 2726 for (int i = 0, len = s.length(); i < len; ) { 2727 int nextPercent = s.indexOf('%', i); 2728 if (s.charAt(i) != '%') { 2729 // This is plain-text part, find the maximal plain-text 2730 // sequence and store it. 2731 int plainTextStart = i; 2732 int plainTextEnd = (nextPercent == -1) ? len: nextPercent; 2733 al.add(new FixedString(s, plainTextStart, plainTextEnd)); 2734 i = plainTextEnd; 2735 } else { 2736 // We have a format specifier 2737 FormatSpecifierParser fsp = new FormatSpecifierParser(s, i + 1); 2738 al.add(fsp.getFormatSpecifier()); 2739 i = fsp.getEndIdx(); 2740 } 2741 } 2742 return al; 2743 } 2744 2745 /** 2746 * Parses the format specifier. 2747 * %[argument_index$][flags][width][.precision][t]conversion 2748 */ 2749 private class FormatSpecifierParser { 2750 private final String format; 2751 private int cursor; 2752 private FormatSpecifier fs; 2753 2754 private String index; 2755 private String flags; 2756 private String width; 2757 private String precision; 2758 private String tT; 2759 private String conv; 2760 2761 private static final String FLAGS = ",-(+# 0<"; 2762 FormatSpecifierParser(String format, int startIdx)2763 public FormatSpecifierParser(String format, int startIdx) { 2764 this.format = format; 2765 cursor = startIdx; 2766 // Index 2767 if (nextIsInt()) { 2768 String nint = nextInt(); 2769 if (peek() == '$') { 2770 index = nint; 2771 advance(); 2772 } else if (nint.charAt(0) == '0') { 2773 // This is a flag, skip to parsing flags. 2774 back(nint.length()); 2775 } else { 2776 // This is the width, skip to parsing precision. 2777 width = nint; 2778 } 2779 } 2780 // Flags 2781 flags = ""; 2782 while (width == null && FLAGS.indexOf(peek()) >= 0) { 2783 flags += advance(); 2784 } 2785 // Width 2786 if (width == null && nextIsInt()) { 2787 width = nextInt(); 2788 } 2789 // Precision 2790 if (peek() == '.') { 2791 advance(); 2792 if (!nextIsInt()) { 2793 throw new IllegalFormatPrecisionException(peek()); 2794 } 2795 precision = nextInt(); 2796 } 2797 // tT 2798 if (peek() == 't' || peek() == 'T') { 2799 tT = String.valueOf(advance()); 2800 } 2801 // Conversion 2802 conv = String.valueOf(advance()); 2803 2804 fs = new FormatSpecifier(index, flags, width, precision, tT, conv); 2805 } 2806 nextInt()2807 private String nextInt() { 2808 int strBegin = cursor; 2809 while (nextIsInt()) { 2810 advance(); 2811 } 2812 return format.substring(strBegin, cursor); 2813 } 2814 nextIsInt()2815 private boolean nextIsInt() { 2816 return !isEnd() && Character.isDigit(peek()); 2817 } 2818 peek()2819 private char peek() { 2820 if (isEnd()) { 2821 throw new UnknownFormatConversionException("End of String"); 2822 } 2823 return format.charAt(cursor); 2824 } 2825 advance()2826 private char advance() { 2827 if (isEnd()) { 2828 throw new UnknownFormatConversionException("End of String"); 2829 } 2830 return format.charAt(cursor++); 2831 } 2832 back(int len)2833 private void back(int len) { 2834 cursor -= len; 2835 } 2836 isEnd()2837 private boolean isEnd() { 2838 return cursor == format.length(); 2839 } 2840 getFormatSpecifier()2841 public FormatSpecifier getFormatSpecifier() { 2842 return fs; 2843 } 2844 getEndIdx()2845 public int getEndIdx() { 2846 return cursor; 2847 } 2848 } 2849 // END Android-changed: changed parse() to manual parsing instead of regex. 2850 2851 private interface FormatString { index()2852 int index(); print(Object arg, Locale l)2853 void print(Object arg, Locale l) throws IOException; toString()2854 String toString(); 2855 } 2856 2857 private class FixedString implements FormatString { 2858 private final String s; 2859 private final int start; 2860 private final int end; FixedString(String s, int start, int end)2861 FixedString(String s, int start, int end) { 2862 this.s = s; 2863 this.start = start; 2864 this.end = end; 2865 } index()2866 public int index() { return -2; } print(Object arg, Locale l)2867 public void print(Object arg, Locale l) 2868 throws IOException { a.append(s, start, end); } toString()2869 public String toString() { return s.substring(start, end); } 2870 } 2871 2872 /** 2873 * Enum for {@code BigDecimal} formatting. 2874 */ 2875 public enum BigDecimalLayoutForm { 2876 /** 2877 * Format the {@code BigDecimal} in computerized scientific notation. 2878 */ 2879 SCIENTIFIC, 2880 2881 /** 2882 * Format the {@code BigDecimal} as a decimal number. 2883 */ 2884 DECIMAL_FLOAT 2885 }; 2886 2887 /** 2888 * Prior to Android 15 (V), validations of argument index, flags, width, and precision 2889 * were lax - it was allowed to use 0 and Integer.MAX_VALUE + 1 as argument index. 2890 * <p> Now it will throw exception, as documentation says. Flag is enabled on Android 15+. 2891 * @hide 2892 */ 2893 @ChangeId 2894 @EnabledSince(targetSdkVersion = VersionCodes.VANILLA_ICE_CREAM) 2895 public static final long ENABLE_STRICT_FORMATTER_VALIDATION = 270674727L; 2896 isStrictValidationEnabled()2897 private static boolean isStrictValidationEnabled() { 2898 return VMRuntime.getSdkVersion() >= VersionCodes.VANILLA_ICE_CREAM 2899 && Compatibility.isChangeEnabled(ENABLE_STRICT_FORMATTER_VALIDATION); 2900 } 2901 2902 private class FormatSpecifier implements FormatString { 2903 2904 private int index = 0; 2905 private Flags f = Flags.NONE; 2906 private int width = -1; 2907 private int precision = -1; 2908 private boolean dt = false; 2909 private char c; 2910 2911 // BEGIN Android-changed: entire String is always consumed. 2912 /* 2913 private void index(String s, int start, int end) { 2914 if (start >= 0) { 2915 try { 2916 // skip the trailing '$' 2917 index = Integer.parseInt(s, start, end - 1, 10); 2918 if (index <= 0) { 2919 throw new IllegalFormatArgumentIndexException(index); 2920 } 2921 } catch (NumberFormatException x) { 2922 throw new IllegalFormatArgumentIndexException(Integer.MIN_VALUE); 2923 } 2924 } 2925 } 2926 */ index(String s)2927 private void index(String s) { 2928 if (s != null) { 2929 try { 2930 // FormatSpecifierParser passes in correct String. 2931 index = Integer.parseInt(s); 2932 // Before V no exception was thrown by this method. 2933 if (isStrictValidationEnabled()) { 2934 if (index <= 0) { 2935 throw new IllegalFormatArgumentIndexException(index); 2936 } 2937 } 2938 } catch (NumberFormatException x) { 2939 // And this exception was swallowed. 2940 if (isStrictValidationEnabled()) { 2941 throw new IllegalFormatArgumentIndexException(Integer.MIN_VALUE); 2942 } else { 2943 // -1 is the default value of the old implementation. index value was left 2944 // untouched in NFE case. 2945 index = -1; 2946 } 2947 } 2948 } 2949 } 2950 // END Android-changed: entire String is always consumed. 2951 index()2952 public int index() { 2953 return index; 2954 } 2955 2956 // Android-changed: entire String is always consumed. 2957 // private void flags(String s, int start, int end) { flags(String s)2958 private void flags(String s) { 2959 // f = Flags.parse(s, start, end); 2960 f = Flags.parse(s, 0, s.length()); 2961 if (f.contains(Flags.PREVIOUS)) 2962 index = -1; 2963 } 2964 2965 // Android-changed: entire String is always consumed. 2966 // private void width(String s, int start, int end) { width(String s)2967 private void width(String s) { 2968 width = -1; 2969 // if (start >= 0) { 2970 if (s != null) { 2971 try { 2972 // width = Integer.parseInt(s, start, end, 10); 2973 width = Integer.parseInt(s); 2974 if (width < 0) 2975 throw new IllegalFormatWidthException(width); 2976 } catch (NumberFormatException x) { 2977 // Android-changed: prior to V this exception was swallowed. 2978 // throw new IllegalFormatWidthException(Integer.MIN_VALUE); 2979 if (isStrictValidationEnabled()) { 2980 throw new IllegalFormatWidthException(Integer.MIN_VALUE); 2981 } 2982 } 2983 } 2984 } 2985 2986 // Android-changed: entire String is always consumed. 2987 // private void precision(String s, int start, int end) { precision(String s)2988 private void precision(String s) { 2989 precision = -1; 2990 // if (start >= 0) { 2991 if (s != null) { 2992 try { 2993 // Android-changed: FormatSpecifierParser passes in correct String. 2994 // skip the leading '.' 2995 // precision = Integer.parseInt(s, start + 1, end, 10); 2996 precision = Integer.parseInt(s); 2997 if (precision < 0) 2998 throw new IllegalFormatPrecisionException(precision); 2999 } catch (NumberFormatException x) { 3000 // Android-changed: prior to V this exception was swallowed. 3001 // throw new IllegalFormatPrecisionException(Integer.MIN_VALUE); 3002 if (isStrictValidationEnabled()) { 3003 throw new IllegalFormatPrecisionException(Integer.MIN_VALUE); 3004 } 3005 } 3006 } 3007 } 3008 conversion(char conv)3009 private void conversion(char conv) { 3010 c = conv; 3011 if (!dt) { 3012 if (!Conversion.isValid(c)) { 3013 throw new UnknownFormatConversionException(String.valueOf(c)); 3014 } 3015 if (Character.isUpperCase(c)) { 3016 f.add(Flags.UPPERCASE); 3017 c = Character.toLowerCase(c); 3018 } 3019 if (Conversion.isText(c)) { 3020 index = -2; 3021 } 3022 } 3023 } 3024 FormatSpecifier(char conv)3025 FormatSpecifier(char conv) { 3026 c = conv; 3027 if (Character.isUpperCase(conv)) { 3028 f = Flags.UPPERCASE; 3029 c = Character.toLowerCase(conv); 3030 } 3031 if (Conversion.isText(conv)) { 3032 index = -2; 3033 } 3034 } 3035 3036 // BEGIN Android-changed: FormatSpecifierParser passes in the values instead of a Matcher. FormatSpecifier(String indexStr, String flagsStr, String widthStr, String precisionStr, String tTStr, String convStr)3037 FormatSpecifier(String indexStr, String flagsStr, String widthStr, 3038 String precisionStr, String tTStr, String convStr) { 3039 index(indexStr); 3040 flags(flagsStr); 3041 width(widthStr); 3042 precision(precisionStr); 3043 3044 if (tTStr != null) { 3045 dt = true; 3046 if (tTStr.equals("T")) { 3047 f.add(Flags.UPPERCASE); 3048 } 3049 } 3050 3051 conversion(convStr.charAt(0)); 3052 // END Android-changed: FormatSpecifierParser passes in the values instead of a Matcher. 3053 if (dt) 3054 checkDateTime(); 3055 else if (Conversion.isGeneral(c)) 3056 checkGeneral(); 3057 else if (Conversion.isCharacter(c)) 3058 checkCharacter(); 3059 else if (Conversion.isInteger(c)) 3060 checkInteger(); 3061 else if (Conversion.isFloat(c)) 3062 checkFloat(); 3063 else if (Conversion.isText(c)) 3064 checkText(); 3065 else 3066 throw new UnknownFormatConversionException(String.valueOf(c)); 3067 } 3068 print(Object arg, Locale l)3069 public void print(Object arg, Locale l) throws IOException { 3070 if (dt) { 3071 printDateTime(arg, l); 3072 return; 3073 } 3074 switch(c) { 3075 case Conversion.DECIMAL_INTEGER: 3076 case Conversion.OCTAL_INTEGER: 3077 case Conversion.HEXADECIMAL_INTEGER: 3078 printInteger(arg, l); 3079 break; 3080 case Conversion.SCIENTIFIC: 3081 case Conversion.GENERAL: 3082 case Conversion.DECIMAL_FLOAT: 3083 case Conversion.HEXADECIMAL_FLOAT: 3084 printFloat(arg, l); 3085 break; 3086 case Conversion.CHARACTER: 3087 printCharacter(arg, l); 3088 break; 3089 case Conversion.BOOLEAN: 3090 printBoolean(arg, l); 3091 break; 3092 case Conversion.STRING: 3093 printString(arg, l); 3094 break; 3095 case Conversion.HASHCODE: 3096 printHashCode(arg, l); 3097 break; 3098 case Conversion.LINE_SEPARATOR: 3099 a.append(System.lineSeparator()); 3100 break; 3101 case Conversion.PERCENT_SIGN: 3102 print("%", l); 3103 break; 3104 default: 3105 assert false; 3106 } 3107 } 3108 printInteger(Object arg, Locale l)3109 private void printInteger(Object arg, Locale l) throws IOException { 3110 if (arg == null) 3111 print("null", l); 3112 else if (arg instanceof Byte) 3113 print(((Byte)arg).byteValue(), l); 3114 else if (arg instanceof Short) 3115 print(((Short)arg).shortValue(), l); 3116 else if (arg instanceof Integer) 3117 print(((Integer)arg).intValue(), l); 3118 else if (arg instanceof Long) 3119 print(((Long)arg).longValue(), l); 3120 else if (arg instanceof BigInteger) 3121 print(((BigInteger)arg), l); 3122 else 3123 failConversion(c, arg); 3124 } 3125 printFloat(Object arg, Locale l)3126 private void printFloat(Object arg, Locale l) throws IOException { 3127 if (arg == null) 3128 print("null", l); 3129 else if (arg instanceof Float) 3130 print(((Float)arg).floatValue(), l); 3131 else if (arg instanceof Double) 3132 print(((Double)arg).doubleValue(), l); 3133 else if (arg instanceof BigDecimal) 3134 print(((BigDecimal)arg), l); 3135 else 3136 failConversion(c, arg); 3137 } 3138 printDateTime(Object arg, Locale l)3139 private void printDateTime(Object arg, Locale l) throws IOException { 3140 if (arg == null) { 3141 print("null", l); 3142 return; 3143 } 3144 Calendar cal = null; 3145 3146 // Instead of Calendar.setLenient(true), perhaps we should 3147 // wrap the IllegalArgumentException that might be thrown? 3148 if (arg instanceof Long) { 3149 // Note that the following method uses an instance of the 3150 // default time zone (TimeZone.getDefaultRef(). 3151 cal = Calendar.getInstance(l == null ? Locale.US : l); 3152 cal.setTimeInMillis((Long)arg); 3153 } else if (arg instanceof Date) { 3154 // Note that the following method uses an instance of the 3155 // default time zone (TimeZone.getDefaultRef(). 3156 cal = Calendar.getInstance(l == null ? Locale.US : l); 3157 cal.setTime((Date)arg); 3158 } else if (arg instanceof Calendar) { 3159 cal = (Calendar) ((Calendar) arg).clone(); 3160 cal.setLenient(true); 3161 } else if (arg instanceof TemporalAccessor) { 3162 print((TemporalAccessor) arg, c, l); 3163 return; 3164 } else { 3165 failConversion(c, arg); 3166 } 3167 // Use the provided locale so that invocations of 3168 // localizedMagnitude() use optimizations for null. 3169 print(cal, c, l); 3170 } 3171 printCharacter(Object arg, Locale l)3172 private void printCharacter(Object arg, Locale l) throws IOException { 3173 if (arg == null) { 3174 print("null", l); 3175 return; 3176 } 3177 String s = null; 3178 if (arg instanceof Character) { 3179 s = ((Character)arg).toString(); 3180 } else if (arg instanceof Byte) { 3181 byte i = (Byte) arg; 3182 if (Character.isValidCodePoint(i)) 3183 s = new String(Character.toChars(i)); 3184 else 3185 throw new IllegalFormatCodePointException(i); 3186 } else if (arg instanceof Short) { 3187 short i = (Short) arg; 3188 if (Character.isValidCodePoint(i)) 3189 s = new String(Character.toChars(i)); 3190 else 3191 throw new IllegalFormatCodePointException(i); 3192 } else if (arg instanceof Integer) { 3193 int i = (Integer) arg; 3194 if (Character.isValidCodePoint(i)) 3195 s = new String(Character.toChars(i)); 3196 else 3197 throw new IllegalFormatCodePointException(i); 3198 } else { 3199 failConversion(c, arg); 3200 } 3201 print(s, l); 3202 } 3203 printString(Object arg, Locale l)3204 private void printString(Object arg, Locale l) throws IOException { 3205 if (arg instanceof Formattable) { 3206 Formatter fmt = Formatter.this; 3207 if (fmt.locale() != l) 3208 fmt = new Formatter(fmt.out(), l); 3209 ((Formattable)arg).formatTo(fmt, f.valueOf(), width, precision); 3210 } else { 3211 if (f.contains(Flags.ALTERNATE)) 3212 failMismatch(Flags.ALTERNATE, 's'); 3213 if (arg == null) 3214 print("null", l); 3215 else 3216 print(arg.toString(), l); 3217 } 3218 } 3219 printBoolean(Object arg, Locale l)3220 private void printBoolean(Object arg, Locale l) throws IOException { 3221 String s; 3222 if (arg != null) 3223 s = ((arg instanceof Boolean) 3224 ? ((Boolean)arg).toString() 3225 : Boolean.toString(true)); 3226 else 3227 s = Boolean.toString(false); 3228 print(s, l); 3229 } 3230 printHashCode(Object arg, Locale l)3231 private void printHashCode(Object arg, Locale l) throws IOException { 3232 String s = (arg == null 3233 ? "null" 3234 : Integer.toHexString(arg.hashCode())); 3235 print(s, l); 3236 } 3237 print(String s, Locale l)3238 private void print(String s, Locale l) throws IOException { 3239 if (precision != -1 && precision < s.length()) 3240 s = s.substring(0, precision); 3241 if (f.contains(Flags.UPPERCASE)) 3242 s = toUpperCaseWithLocale(s, l); 3243 appendJustified(a, s); 3244 } 3245 toUpperCaseWithLocale(String s, Locale l)3246 private String toUpperCaseWithLocale(String s, Locale l) { 3247 return s.toUpperCase(Objects.requireNonNullElse(l, 3248 Locale.getDefault(Locale.Category.FORMAT))); 3249 } 3250 appendJustified(Appendable a, CharSequence cs)3251 private void appendJustified(Appendable a, CharSequence cs) throws IOException { 3252 if (width == -1) { 3253 a.append(cs); 3254 return; 3255 } 3256 boolean padRight = f.contains(Flags.LEFT_JUSTIFY); 3257 int sp = width - cs.length(); 3258 if (padRight) { 3259 a.append(cs); 3260 } 3261 for (int i = 0; i < sp; i++) { 3262 a.append(' '); 3263 } 3264 if (!padRight) { 3265 a.append(cs); 3266 } 3267 } 3268 toString()3269 public String toString() { 3270 StringBuilder sb = new StringBuilder("%"); 3271 // Flags.UPPERCASE is set internally for legal conversions. 3272 Flags dupf = f.dup().remove(Flags.UPPERCASE); 3273 sb.append(dupf.toString()); 3274 if (index > 0) 3275 sb.append(index).append('$'); 3276 if (width != -1) 3277 sb.append(width); 3278 if (precision != -1) 3279 sb.append('.').append(precision); 3280 if (dt) 3281 sb.append(f.contains(Flags.UPPERCASE) ? 'T' : 't'); 3282 sb.append(f.contains(Flags.UPPERCASE) 3283 ? Character.toUpperCase(c) : c); 3284 return sb.toString(); 3285 } 3286 checkGeneral()3287 private void checkGeneral() { 3288 if ((c == Conversion.BOOLEAN || c == Conversion.HASHCODE) 3289 && f.contains(Flags.ALTERNATE)) 3290 failMismatch(Flags.ALTERNATE, c); 3291 // '-' requires a width 3292 if (width == -1 && f.contains(Flags.LEFT_JUSTIFY)) 3293 throw new MissingFormatWidthException(toString()); 3294 checkBadFlags(Flags.PLUS, Flags.LEADING_SPACE, Flags.ZERO_PAD, 3295 Flags.GROUP, Flags.PARENTHESES); 3296 } 3297 checkDateTime()3298 private void checkDateTime() { 3299 if (precision != -1) 3300 throw new IllegalFormatPrecisionException(precision); 3301 if (!DateTime.isValid(c)) 3302 throw new UnknownFormatConversionException("t" + c); 3303 checkBadFlags(Flags.ALTERNATE, Flags.PLUS, Flags.LEADING_SPACE, 3304 Flags.ZERO_PAD, Flags.GROUP, Flags.PARENTHESES); 3305 // '-' requires a width 3306 if (width == -1 && f.contains(Flags.LEFT_JUSTIFY)) 3307 throw new MissingFormatWidthException(toString()); 3308 } 3309 checkCharacter()3310 private void checkCharacter() { 3311 if (precision != -1) 3312 throw new IllegalFormatPrecisionException(precision); 3313 checkBadFlags(Flags.ALTERNATE, Flags.PLUS, Flags.LEADING_SPACE, 3314 Flags.ZERO_PAD, Flags.GROUP, Flags.PARENTHESES); 3315 // '-' requires a width 3316 if (width == -1 && f.contains(Flags.LEFT_JUSTIFY)) 3317 throw new MissingFormatWidthException(toString()); 3318 } 3319 checkInteger()3320 private void checkInteger() { 3321 checkNumeric(); 3322 if (precision != -1) 3323 throw new IllegalFormatPrecisionException(precision); 3324 3325 if (c == Conversion.DECIMAL_INTEGER) 3326 checkBadFlags(Flags.ALTERNATE); 3327 else if (c == Conversion.OCTAL_INTEGER) 3328 checkBadFlags(Flags.GROUP); 3329 else 3330 checkBadFlags(Flags.GROUP); 3331 } 3332 checkBadFlags(Flags .... badFlags)3333 private void checkBadFlags(Flags ... badFlags) { 3334 for (Flags badFlag : badFlags) 3335 if (f.contains(badFlag)) 3336 failMismatch(badFlag, c); 3337 } 3338 checkFloat()3339 private void checkFloat() { 3340 checkNumeric(); 3341 if (c == Conversion.DECIMAL_FLOAT) { 3342 } else if (c == Conversion.HEXADECIMAL_FLOAT) { 3343 checkBadFlags(Flags.PARENTHESES, Flags.GROUP); 3344 } else if (c == Conversion.SCIENTIFIC) { 3345 checkBadFlags(Flags.GROUP); 3346 } else if (c == Conversion.GENERAL) { 3347 checkBadFlags(Flags.ALTERNATE); 3348 } 3349 } 3350 checkNumeric()3351 private void checkNumeric() { 3352 if (width != -1 && width < 0) 3353 throw new IllegalFormatWidthException(width); 3354 3355 if (precision != -1 && precision < 0) 3356 throw new IllegalFormatPrecisionException(precision); 3357 3358 // '-' and '0' require a width 3359 if (width == -1 3360 && (f.contains(Flags.LEFT_JUSTIFY) || f.contains(Flags.ZERO_PAD))) 3361 throw new MissingFormatWidthException(toString()); 3362 3363 // bad combination 3364 if ((f.contains(Flags.PLUS) && f.contains(Flags.LEADING_SPACE)) 3365 || (f.contains(Flags.LEFT_JUSTIFY) && f.contains(Flags.ZERO_PAD))) 3366 throw new IllegalFormatFlagsException(f.toString()); 3367 } 3368 checkText()3369 private void checkText() { 3370 if (precision != -1) 3371 throw new IllegalFormatPrecisionException(precision); 3372 switch (c) { 3373 case Conversion.PERCENT_SIGN: 3374 if (f.valueOf() != Flags.LEFT_JUSTIFY.valueOf() 3375 && f.valueOf() != Flags.NONE.valueOf()) 3376 throw new IllegalFormatFlagsException(f.toString()); 3377 // '-' requires a width 3378 if (width == -1 && f.contains(Flags.LEFT_JUSTIFY)) 3379 throw new MissingFormatWidthException(toString()); 3380 break; 3381 case Conversion.LINE_SEPARATOR: 3382 if (width != -1) 3383 throw new IllegalFormatWidthException(width); 3384 if (f.valueOf() != Flags.NONE.valueOf()) 3385 throw new IllegalFormatFlagsException(f.toString()); 3386 break; 3387 default: 3388 assert false; 3389 } 3390 } 3391 print(byte value, Locale l)3392 private void print(byte value, Locale l) throws IOException { 3393 long v = value; 3394 if (value < 0 3395 && (c == Conversion.OCTAL_INTEGER 3396 || c == Conversion.HEXADECIMAL_INTEGER)) { 3397 v += (1L << 8); 3398 } 3399 print(v, l); 3400 } 3401 print(short value, Locale l)3402 private void print(short value, Locale l) throws IOException { 3403 long v = value; 3404 if (value < 0 3405 && (c == Conversion.OCTAL_INTEGER 3406 || c == Conversion.HEXADECIMAL_INTEGER)) { 3407 v += (1L << 16); 3408 assert v >= 0 : v; 3409 } 3410 print(v, l); 3411 } 3412 print(int value, Locale l)3413 private void print(int value, Locale l) throws IOException { 3414 long v = value; 3415 if (value < 0 3416 && (c == Conversion.OCTAL_INTEGER 3417 || c == Conversion.HEXADECIMAL_INTEGER)) { 3418 v += (1L << 32); 3419 assert v >= 0 : v; 3420 } 3421 print(v, l); 3422 } 3423 print(long value, Locale l)3424 private void print(long value, Locale l) throws IOException { 3425 3426 StringBuilder sb = new StringBuilder(); 3427 3428 if (c == Conversion.DECIMAL_INTEGER) { 3429 boolean neg = value < 0; 3430 String valueStr = Long.toString(value, 10); 3431 3432 // leading sign indicator 3433 leadingSign(sb, neg); 3434 3435 // the value 3436 localizedMagnitude(sb, valueStr, neg ? 1 : 0, f, adjustWidth(width, f, neg), l); 3437 3438 // trailing sign indicator 3439 trailingSign(sb, neg); 3440 } else if (c == Conversion.OCTAL_INTEGER) { 3441 checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE, 3442 Flags.PLUS); 3443 String s = Long.toOctalString(value); 3444 int len = (f.contains(Flags.ALTERNATE) 3445 ? s.length() + 1 3446 : s.length()); 3447 3448 // apply ALTERNATE (radix indicator for octal) before ZERO_PAD 3449 if (f.contains(Flags.ALTERNATE)) 3450 sb.append('0'); 3451 if (f.contains(Flags.ZERO_PAD)) { 3452 trailingZeros(sb, width - len); 3453 } 3454 sb.append(s); 3455 } else if (c == Conversion.HEXADECIMAL_INTEGER) { 3456 checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE, 3457 Flags.PLUS); 3458 String s = Long.toHexString(value); 3459 int len = (f.contains(Flags.ALTERNATE) 3460 ? s.length() + 2 3461 : s.length()); 3462 3463 // apply ALTERNATE (radix indicator for hex) before ZERO_PAD 3464 if (f.contains(Flags.ALTERNATE)) 3465 sb.append(f.contains(Flags.UPPERCASE) ? "0X" : "0x"); 3466 if (f.contains(Flags.ZERO_PAD)) { 3467 trailingZeros(sb, width - len); 3468 } 3469 if (f.contains(Flags.UPPERCASE)) 3470 s = toUpperCaseWithLocale(s, l); 3471 sb.append(s); 3472 } 3473 3474 // justify based on width 3475 appendJustified(a, sb); 3476 } 3477 3478 // neg := val < 0 3479 private StringBuilder leadingSign(StringBuilder sb, boolean neg) { 3480 if (!neg) { 3481 if (f.contains(Flags.PLUS)) { 3482 sb.append('+'); 3483 } else if (f.contains(Flags.LEADING_SPACE)) { 3484 sb.append(' '); 3485 } 3486 } else { 3487 if (f.contains(Flags.PARENTHESES)) 3488 sb.append('('); 3489 else 3490 sb.append('-'); 3491 } 3492 return sb; 3493 } 3494 3495 // neg := val < 0 3496 private StringBuilder trailingSign(StringBuilder sb, boolean neg) { 3497 if (neg && f.contains(Flags.PARENTHESES)) 3498 sb.append(')'); 3499 return sb; 3500 } 3501 3502 private void print(BigInteger value, Locale l) throws IOException { 3503 StringBuilder sb = new StringBuilder(); 3504 boolean neg = value.signum() == -1; 3505 BigInteger v = value.abs(); 3506 3507 // leading sign indicator 3508 leadingSign(sb, neg); 3509 3510 // the value 3511 if (c == Conversion.DECIMAL_INTEGER) { 3512 localizedMagnitude(sb, v.toString(), 0, f, adjustWidth(width, f, neg), l); 3513 } else if (c == Conversion.OCTAL_INTEGER) { 3514 String s = v.toString(8); 3515 3516 int len = s.length() + sb.length(); 3517 if (neg && f.contains(Flags.PARENTHESES)) 3518 len++; 3519 3520 // apply ALTERNATE (radix indicator for octal) before ZERO_PAD 3521 if (f.contains(Flags.ALTERNATE)) { 3522 len++; 3523 sb.append('0'); 3524 } 3525 if (f.contains(Flags.ZERO_PAD)) { 3526 trailingZeros(sb, width - len); 3527 } 3528 sb.append(s); 3529 } else if (c == Conversion.HEXADECIMAL_INTEGER) { 3530 String s = v.toString(16); 3531 3532 int len = s.length() + sb.length(); 3533 if (neg && f.contains(Flags.PARENTHESES)) 3534 len++; 3535 3536 // apply ALTERNATE (radix indicator for hex) before ZERO_PAD 3537 if (f.contains(Flags.ALTERNATE)) { 3538 len += 2; 3539 sb.append(f.contains(Flags.UPPERCASE) ? "0X" : "0x"); 3540 } 3541 if (f.contains(Flags.ZERO_PAD)) { 3542 trailingZeros(sb, width - len); 3543 } 3544 if (f.contains(Flags.UPPERCASE)) 3545 s = toUpperCaseWithLocale(s, l); 3546 sb.append(s); 3547 } 3548 3549 // trailing sign indicator 3550 trailingSign(sb, (value.signum() == -1)); 3551 3552 // justify based on width 3553 appendJustified(a, sb); 3554 } 3555 3556 private void print(float value, Locale l) throws IOException { 3557 print((double) value, l); 3558 } 3559 3560 private void print(double value, Locale l) throws IOException { 3561 StringBuilder sb = new StringBuilder(); 3562 boolean neg = Double.compare(value, 0.0) == -1; 3563 3564 if (!Double.isNaN(value)) { 3565 double v = Math.abs(value); 3566 3567 // leading sign indicator 3568 leadingSign(sb, neg); 3569 3570 // the value 3571 if (!Double.isInfinite(v)) 3572 print(sb, v, l, f, c, precision, neg); 3573 else 3574 sb.append(f.contains(Flags.UPPERCASE) 3575 ? "INFINITY" : "Infinity"); 3576 3577 // trailing sign indicator 3578 trailingSign(sb, neg); 3579 } else { 3580 sb.append(f.contains(Flags.UPPERCASE) ? "NAN" : "NaN"); 3581 } 3582 3583 // justify based on width 3584 appendJustified(a, sb); 3585 } 3586 3587 // !Double.isInfinite(value) && !Double.isNaN(value) 3588 private void print(StringBuilder sb, double value, Locale l, 3589 Flags f, char c, int precision, boolean neg) 3590 throws IOException 3591 { 3592 if (c == Conversion.SCIENTIFIC) { 3593 // Create a new FormattedFloatingDecimal with the desired 3594 // precision. 3595 int prec = (precision == -1 ? 6 : precision); 3596 3597 FormattedFloatingDecimal fd 3598 = FormattedFloatingDecimal.valueOf(value, prec, 3599 FormattedFloatingDecimal.Form.SCIENTIFIC); 3600 3601 StringBuilder mant = new StringBuilder().append(fd.getMantissa()); 3602 addZeros(mant, prec); 3603 3604 // If the precision is zero and the '#' flag is set, add the 3605 // requested decimal point. 3606 if (f.contains(Flags.ALTERNATE) && (prec == 0)) { 3607 mant.append('.'); 3608 } 3609 3610 char[] exp = (value == 0.0) 3611 ? new char[] {'+','0','0'} : fd.getExponent(); 3612 3613 int newW = width; 3614 if (width != -1) { 3615 newW = adjustWidth(width - exp.length - 1, f, neg); 3616 } 3617 localizedMagnitude(sb, mant, 0, f, newW, l); 3618 3619 // BEGIN Android-changed: Use localized exponent separator for %e. 3620 Locale separatorLocale = (l != null) ? l : Locale.getDefault(); 3621 DecimalFormatData formatData = DecimalFormatData.getInstance(separatorLocale); 3622 sb.append(f.contains(Flags.UPPERCASE) ? 3623 formatData.getExponentSeparator().toUpperCase(separatorLocale) : 3624 formatData.getExponentSeparator().toLowerCase(separatorLocale)); 3625 // END Android-changed: Use localized exponent separator for %e. 3626 3627 char sign = exp[0]; 3628 assert(sign == '+' || sign == '-'); 3629 sb.append(sign); 3630 3631 localizedMagnitudeExp(sb, exp, 1, l); 3632 } else if (c == Conversion.DECIMAL_FLOAT) { 3633 // Create a new FormattedFloatingDecimal with the desired 3634 // precision. 3635 int prec = (precision == -1 ? 6 : precision); 3636 3637 FormattedFloatingDecimal fd 3638 = FormattedFloatingDecimal.valueOf(value, prec, 3639 FormattedFloatingDecimal.Form.DECIMAL_FLOAT); 3640 3641 StringBuilder mant = new StringBuilder().append(fd.getMantissa()); 3642 addZeros(mant, prec); 3643 3644 // If the precision is zero and the '#' flag is set, add the 3645 // requested decimal point. 3646 if (f.contains(Flags.ALTERNATE) && (prec == 0)) 3647 mant.append('.'); 3648 3649 int newW = width; 3650 if (width != -1) 3651 newW = adjustWidth(width, f, neg); 3652 localizedMagnitude(sb, mant, 0, f, newW, l); 3653 } else if (c == Conversion.GENERAL) { 3654 int prec = precision; 3655 if (precision == -1) 3656 prec = 6; 3657 else if (precision == 0) 3658 prec = 1; 3659 3660 char[] exp; 3661 StringBuilder mant = new StringBuilder(); 3662 int expRounded; 3663 if (value == 0.0) { 3664 exp = null; 3665 mant.append('0'); 3666 expRounded = 0; 3667 } else { 3668 FormattedFloatingDecimal fd 3669 = FormattedFloatingDecimal.valueOf(value, prec, 3670 FormattedFloatingDecimal.Form.GENERAL); 3671 exp = fd.getExponent(); 3672 mant.append(fd.getMantissa()); 3673 expRounded = fd.getExponentRounded(); 3674 } 3675 3676 if (exp != null) { 3677 prec -= 1; 3678 } else { 3679 prec -= expRounded + 1; 3680 } 3681 3682 addZeros(mant, prec); 3683 // If the precision is zero and the '#' flag is set, add the 3684 // requested decimal point. 3685 if (f.contains(Flags.ALTERNATE) && (prec == 0)) { 3686 mant.append('.'); 3687 } 3688 3689 int newW = width; 3690 if (width != -1) { 3691 if (exp != null) 3692 newW = adjustWidth(width - exp.length - 1, f, neg); 3693 else 3694 newW = adjustWidth(width, f, neg); 3695 } 3696 localizedMagnitude(sb, mant, 0, f, newW, l); 3697 3698 if (exp != null) { 3699 sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e'); 3700 3701 char sign = exp[0]; 3702 assert(sign == '+' || sign == '-'); 3703 sb.append(sign); 3704 3705 localizedMagnitudeExp(sb, exp, 1, l); 3706 } 3707 } else if (c == Conversion.HEXADECIMAL_FLOAT) { 3708 int prec = precision; 3709 if (precision == -1) 3710 // assume that we want all of the digits 3711 prec = 0; 3712 else if (precision == 0) 3713 prec = 1; 3714 3715 String s = hexDouble(value, prec); 3716 3717 StringBuilder va = new StringBuilder(); 3718 boolean upper = f.contains(Flags.UPPERCASE); 3719 sb.append(upper ? "0X" : "0x"); 3720 3721 if (f.contains(Flags.ZERO_PAD)) { 3722 int leadingCharacters = 2; 3723 if(f.contains(Flags.LEADING_SPACE) || 3724 f.contains(Flags.PLUS) || neg) { 3725 leadingCharacters = 3; 3726 } 3727 trailingZeros(sb, width - s.length() - leadingCharacters); 3728 } 3729 3730 int idx = s.indexOf('p'); 3731 if (upper) { 3732 String tmp = s.substring(0, idx); 3733 // don't localize hex 3734 tmp = tmp.toUpperCase(Locale.ROOT); 3735 va.append(tmp); 3736 } else { 3737 va.append(s, 0, idx); 3738 } 3739 if (prec != 0) { 3740 addZeros(va, prec); 3741 } 3742 sb.append(va); 3743 sb.append(upper ? 'P' : 'p'); 3744 sb.append(s, idx+1, s.length()); 3745 } 3746 } 3747 3748 // Add zeros to the requested precision. 3749 private void addZeros(StringBuilder sb, int prec) { 3750 // Look for the dot. If we don't find one, the we'll need to add 3751 // it before we add the zeros. 3752 int len = sb.length(); 3753 int i; 3754 for (i = 0; i < len; i++) { 3755 if (sb.charAt(i) == '.') { 3756 break; 3757 } 3758 } 3759 boolean needDot = false; 3760 if (i == len) { 3761 needDot = true; 3762 } 3763 3764 // Determine existing precision. 3765 int outPrec = len - i - (needDot ? 0 : 1); 3766 assert (outPrec <= prec); 3767 if (outPrec == prec) { 3768 return; 3769 } 3770 3771 // Add dot if previously determined to be necessary. 3772 if (needDot) { 3773 sb.append('.'); 3774 } 3775 3776 // Add zeros. 3777 trailingZeros(sb, prec - outPrec); 3778 } 3779 3780 // Method assumes that d > 0. 3781 private String hexDouble(double d, int prec) { 3782 // Let Double.toHexString handle simple cases 3783 if (!Double.isFinite(d) || d == 0.0 || prec == 0 || prec >= 13) { 3784 // remove "0x" 3785 return Double.toHexString(d).substring(2); 3786 } else { 3787 assert(prec >= 1 && prec <= 12); 3788 3789 int exponent = Math.getExponent(d); 3790 boolean subnormal 3791 = (exponent == Double.MIN_EXPONENT - 1); 3792 3793 // If this is subnormal input so normalize (could be faster to 3794 // do as integer operation). 3795 if (subnormal) { 3796 double scaleUp = Math.scalb(1.0, 54); 3797 d *= scaleUp; 3798 // Calculate the exponent. This is not just exponent + 54 3799 // since the former is not the normalized exponent. 3800 exponent = Math.getExponent(d); 3801 assert exponent >= Double.MIN_EXPONENT && 3802 exponent <= Double.MAX_EXPONENT: exponent; 3803 } 3804 3805 int precision = 1 + prec*4; 3806 int shiftDistance 3807 = DoubleConsts.SIGNIFICAND_WIDTH - precision; 3808 assert(shiftDistance >= 1 && shiftDistance < DoubleConsts.SIGNIFICAND_WIDTH); 3809 3810 long doppel = Double.doubleToLongBits(d); 3811 // Deterime the number of bits to keep. 3812 long newSignif 3813 = (doppel & (DoubleConsts.EXP_BIT_MASK 3814 | DoubleConsts.SIGNIF_BIT_MASK)) 3815 >> shiftDistance; 3816 // Bits to round away. 3817 long roundingBits = doppel & ~(~0L << shiftDistance); 3818 3819 // To decide how to round, look at the low-order bit of the 3820 // working significand, the highest order discarded bit (the 3821 // round bit) and whether any of the lower order discarded bits 3822 // are nonzero (the sticky bit). 3823 3824 boolean leastZero = (newSignif & 0x1L) == 0L; 3825 boolean round 3826 = ((1L << (shiftDistance - 1) ) & roundingBits) != 0L; 3827 boolean sticky = shiftDistance > 1 && 3828 (~(1L<< (shiftDistance - 1)) & roundingBits) != 0; 3829 if((leastZero && round && sticky) || (!leastZero && round)) { 3830 newSignif++; 3831 } 3832 3833 long signBit = doppel & DoubleConsts.SIGN_BIT_MASK; 3834 newSignif = signBit | (newSignif << shiftDistance); 3835 double result = Double.longBitsToDouble(newSignif); 3836 3837 if (Double.isInfinite(result) ) { 3838 // Infinite result generated by rounding 3839 return "1.0p1024"; 3840 } else { 3841 String res = Double.toHexString(result).substring(2); 3842 if (!subnormal) 3843 return res; 3844 else { 3845 // Create a normalized subnormal string. 3846 int idx = res.indexOf('p'); 3847 if (idx == -1) { 3848 // No 'p' character in hex string. 3849 assert false; 3850 return null; 3851 } else { 3852 // Get exponent and append at the end. 3853 String exp = res.substring(idx + 1); 3854 int iexp = Integer.parseInt(exp) -54; 3855 return res.substring(0, idx) + "p" 3856 + Integer.toString(iexp); 3857 } 3858 } 3859 } 3860 } 3861 } 3862 print(BigDecimal value, Locale l)3863 private void print(BigDecimal value, Locale l) throws IOException { 3864 if (c == Conversion.HEXADECIMAL_FLOAT) 3865 failConversion(c, value); 3866 StringBuilder sb = new StringBuilder(); 3867 boolean neg = value.signum() == -1; 3868 BigDecimal v = value.abs(); 3869 // leading sign indicator 3870 leadingSign(sb, neg); 3871 3872 // the value 3873 print(sb, v, l, f, c, precision, neg); 3874 3875 // trailing sign indicator 3876 trailingSign(sb, neg); 3877 3878 // justify based on width 3879 appendJustified(a, sb); 3880 } 3881 3882 // value > 0 print(StringBuilder sb, BigDecimal value, Locale l, Flags f, char c, int precision, boolean neg)3883 private void print(StringBuilder sb, BigDecimal value, Locale l, 3884 Flags f, char c, int precision, boolean neg) 3885 throws IOException 3886 { 3887 if (c == Conversion.SCIENTIFIC) { 3888 // Create a new BigDecimal with the desired precision. 3889 int prec = (precision == -1 ? 6 : precision); 3890 int scale = value.scale(); 3891 int origPrec = value.precision(); 3892 int nzeros = 0; 3893 int compPrec; 3894 3895 if (prec > origPrec - 1) { 3896 compPrec = origPrec; 3897 nzeros = prec - (origPrec - 1); 3898 } else { 3899 compPrec = prec + 1; 3900 } 3901 3902 MathContext mc = new MathContext(compPrec); 3903 BigDecimal v 3904 = new BigDecimal(value.unscaledValue(), scale, mc); 3905 3906 BigDecimalLayout bdl 3907 = new BigDecimalLayout(v.unscaledValue(), v.scale(), 3908 BigDecimalLayoutForm.SCIENTIFIC); 3909 3910 StringBuilder mant = bdl.mantissa(); 3911 3912 // Add a decimal point if necessary. The mantissa may not 3913 // contain a decimal point if the scale is zero (the internal 3914 // representation has no fractional part) or the original 3915 // precision is one. Append a decimal point if '#' is set or if 3916 // we require zero padding to get to the requested precision. 3917 if ((origPrec == 1 || !bdl.hasDot()) 3918 && (nzeros > 0 || (f.contains(Flags.ALTERNATE)))) { 3919 mant.append('.'); 3920 } 3921 3922 // Add trailing zeros in the case precision is greater than 3923 // the number of available digits after the decimal separator. 3924 trailingZeros(mant, nzeros); 3925 3926 StringBuilder exp = bdl.exponent(); 3927 int newW = width; 3928 if (width != -1) { 3929 newW = adjustWidth(width - exp.length() - 1, f, neg); 3930 } 3931 localizedMagnitude(sb, mant, 0, f, newW, l); 3932 3933 sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e'); 3934 3935 Flags flags = f.dup().remove(Flags.GROUP); 3936 char sign = exp.charAt(0); 3937 assert(sign == '+' || sign == '-'); 3938 sb.append(sign); 3939 3940 sb.append(localizedMagnitude(null, exp, 1, flags, -1, l)); 3941 } else if (c == Conversion.DECIMAL_FLOAT) { 3942 // Create a new BigDecimal with the desired precision. 3943 int prec = (precision == -1 ? 6 : precision); 3944 int scale = value.scale(); 3945 3946 if (scale > prec) { 3947 // more "scale" digits than the requested "precision" 3948 int compPrec = value.precision(); 3949 if (compPrec <= scale) { 3950 // case of 0.xxxxxx 3951 value = value.setScale(prec, RoundingMode.HALF_UP); 3952 } else { 3953 compPrec -= (scale - prec); 3954 value = new BigDecimal(value.unscaledValue(), 3955 scale, 3956 new MathContext(compPrec)); 3957 } 3958 } 3959 BigDecimalLayout bdl = new BigDecimalLayout( 3960 value.unscaledValue(), 3961 value.scale(), 3962 BigDecimalLayoutForm.DECIMAL_FLOAT); 3963 3964 StringBuilder mant = bdl.mantissa(); 3965 int nzeros = (bdl.scale() < prec ? prec - bdl.scale() : 0); 3966 3967 // Add a decimal point if necessary. The mantissa may not 3968 // contain a decimal point if the scale is zero (the internal 3969 // representation has no fractional part). Append a decimal 3970 // point if '#' is set or we require zero padding to get to the 3971 // requested precision. 3972 if (bdl.scale() == 0 && (f.contains(Flags.ALTERNATE) 3973 || nzeros > 0)) { 3974 mant.append('.'); 3975 } 3976 3977 // Add trailing zeros if the precision is greater than the 3978 // number of available digits after the decimal separator. 3979 trailingZeros(mant, nzeros); 3980 3981 localizedMagnitude(sb, mant, 0, f, adjustWidth(width, f, neg), l); 3982 } else if (c == Conversion.GENERAL) { 3983 int prec = precision; 3984 if (precision == -1) 3985 prec = 6; 3986 else if (precision == 0) 3987 prec = 1; 3988 3989 value = value.round(new MathContext(prec)); 3990 if ((value.equals(BigDecimal.ZERO)) 3991 || ((value.compareTo(BigDecimal.valueOf(1, 4)) != -1) 3992 && (value.compareTo(BigDecimal.valueOf(1, -prec)) == -1))) { 3993 3994 int e = - value.scale() 3995 + (value.unscaledValue().toString().length() - 1); 3996 3997 // xxx.yyy 3998 // g precision (# sig digits) = #x + #y 3999 // f precision = #y 4000 // exponent = #x - 1 4001 // => f precision = g precision - exponent - 1 4002 // 0.000zzz 4003 // g precision (# sig digits) = #z 4004 // f precision = #0 (after '.') + #z 4005 // exponent = - #0 (after '.') - 1 4006 // => f precision = g precision - exponent - 1 4007 prec = prec - e - 1; 4008 4009 print(sb, value, l, f, Conversion.DECIMAL_FLOAT, prec, 4010 neg); 4011 } else { 4012 print(sb, value, l, f, Conversion.SCIENTIFIC, prec - 1, neg); 4013 } 4014 } else if (c == Conversion.HEXADECIMAL_FLOAT) { 4015 // This conversion isn't supported. The error should be 4016 // reported earlier. 4017 assert false; 4018 } 4019 } 4020 4021 private class BigDecimalLayout { 4022 private StringBuilder mant; 4023 private StringBuilder exp; 4024 private boolean dot = false; 4025 private int scale; 4026 BigDecimalLayout(BigInteger intVal, int scale, BigDecimalLayoutForm form)4027 public BigDecimalLayout(BigInteger intVal, int scale, BigDecimalLayoutForm form) { 4028 layout(intVal, scale, form); 4029 } 4030 hasDot()4031 public boolean hasDot() { 4032 return dot; 4033 } 4034 scale()4035 public int scale() { 4036 return scale; 4037 } 4038 mantissa()4039 public StringBuilder mantissa() { 4040 return mant; 4041 } 4042 4043 // The exponent will be formatted as a sign ('+' or '-') followed 4044 // by the exponent zero-padded to include at least two digits. exponent()4045 public StringBuilder exponent() { 4046 return exp; 4047 } 4048 layout(BigInteger intVal, int scale, BigDecimalLayoutForm form)4049 private void layout(BigInteger intVal, int scale, BigDecimalLayoutForm form) { 4050 String coeff = intVal.toString(); 4051 this.scale = scale; 4052 4053 // Construct a buffer, with sufficient capacity for all cases. 4054 // If E-notation is needed, length will be: +1 if negative, +1 4055 // if '.' needed, +2 for "E+", + up to 10 for adjusted 4056 // exponent. Otherwise it could have +1 if negative, plus 4057 // leading "0.00000" 4058 int len = coeff.length(); 4059 mant = new StringBuilder(len + 14); 4060 4061 if (scale == 0) { 4062 if (len > 1) { 4063 mant.append(coeff.charAt(0)); 4064 if (form == BigDecimalLayoutForm.SCIENTIFIC) { 4065 mant.append('.'); 4066 dot = true; 4067 mant.append(coeff, 1, len); 4068 exp = new StringBuilder("+"); 4069 if (len < 10) { 4070 exp.append('0').append(len - 1); 4071 } else { 4072 exp.append(len - 1); 4073 } 4074 } else { 4075 mant.append(coeff, 1, len); 4076 } 4077 } else { 4078 mant.append(coeff); 4079 if (form == BigDecimalLayoutForm.SCIENTIFIC) { 4080 exp = new StringBuilder("+00"); 4081 } 4082 } 4083 } else if (form == BigDecimalLayoutForm.DECIMAL_FLOAT) { 4084 // count of padding zeros 4085 4086 if (scale >= len) { 4087 // 0.xxx form 4088 mant.append("0."); 4089 dot = true; 4090 trailingZeros(mant, scale - len); 4091 mant.append(coeff); 4092 } else { 4093 if (scale > 0) { 4094 // xx.xx form 4095 int pad = len - scale; 4096 mant.append(coeff, 0, pad); 4097 mant.append('.'); 4098 dot = true; 4099 mant.append(coeff, pad, len); 4100 } else { // scale < 0 4101 // xx form 4102 mant.append(coeff, 0, len); 4103 if (intVal.signum() != 0) { 4104 trailingZeros(mant, -scale); 4105 } 4106 this.scale = 0; 4107 } 4108 } 4109 } else { 4110 // x.xxx form 4111 mant.append(coeff.charAt(0)); 4112 if (len > 1) { 4113 mant.append('.'); 4114 dot = true; 4115 mant.append(coeff, 1, len); 4116 } 4117 exp = new StringBuilder(); 4118 long adjusted = -(long) scale + (len - 1); 4119 if (adjusted != 0) { 4120 long abs = Math.abs(adjusted); 4121 // require sign 4122 exp.append(adjusted < 0 ? '-' : '+'); 4123 if (abs < 10) { 4124 exp.append('0'); 4125 } 4126 exp.append(abs); 4127 } else { 4128 exp.append("+00"); 4129 } 4130 } 4131 } 4132 } 4133 4134 private int adjustWidth(int width, Flags f, boolean neg) { 4135 int newW = width; 4136 if (newW != -1 && neg && f.contains(Flags.PARENTHESES)) 4137 newW--; 4138 return newW; 4139 } 4140 4141 // Add trailing zeros 4142 private void trailingZeros(StringBuilder sb, int nzeros) { 4143 for (int i = 0; i < nzeros; i++) { 4144 sb.append('0'); 4145 } 4146 } 4147 4148 private void print(Calendar t, char c, Locale l) throws IOException { 4149 StringBuilder sb = new StringBuilder(); 4150 print(sb, t, c, l); 4151 4152 // justify based on width 4153 if (f.contains(Flags.UPPERCASE)) { 4154 appendJustified(a, toUpperCaseWithLocale(sb.toString(), l)); 4155 } else { 4156 appendJustified(a, sb); 4157 } 4158 } 4159 4160 private Appendable print(StringBuilder sb, Calendar t, char c, Locale l) 4161 throws IOException { 4162 if (sb == null) 4163 sb = new StringBuilder(); 4164 switch (c) { 4165 case DateTime.HOUR_OF_DAY_0: // 'H' (00 - 23) 4166 case DateTime.HOUR_0: // 'I' (01 - 12) 4167 case DateTime.HOUR_OF_DAY: // 'k' (0 - 23) -- like H 4168 case DateTime.HOUR: { // 'l' (1 - 12) -- like I 4169 int i = t.get(Calendar.HOUR_OF_DAY); 4170 if (c == DateTime.HOUR_0 || c == DateTime.HOUR) 4171 i = (i == 0 || i == 12 ? 12 : i % 12); 4172 Flags flags = (c == DateTime.HOUR_OF_DAY_0 4173 || c == DateTime.HOUR_0 4174 ? Flags.ZERO_PAD 4175 : Flags.NONE); 4176 sb.append(localizedMagnitude(null, i, flags, 2, l)); 4177 break; 4178 } 4179 case DateTime.MINUTE: { // 'M' (00 - 59) 4180 int i = t.get(Calendar.MINUTE); 4181 Flags flags = Flags.ZERO_PAD; 4182 sb.append(localizedMagnitude(null, i, flags, 2, l)); 4183 break; 4184 } 4185 case DateTime.NANOSECOND: { // 'N' (000000000 - 999999999) 4186 int i = t.get(Calendar.MILLISECOND) * 1000000; 4187 Flags flags = Flags.ZERO_PAD; 4188 sb.append(localizedMagnitude(null, i, flags, 9, l)); 4189 break; 4190 } 4191 case DateTime.MILLISECOND: { // 'L' (000 - 999) 4192 int i = t.get(Calendar.MILLISECOND); 4193 Flags flags = Flags.ZERO_PAD; 4194 sb.append(localizedMagnitude(null, i, flags, 3, l)); 4195 break; 4196 } 4197 case DateTime.MILLISECOND_SINCE_EPOCH: { // 'Q' (0 - 99...?) 4198 long i = t.getTimeInMillis(); 4199 Flags flags = Flags.NONE; 4200 sb.append(localizedMagnitude(null, i, flags, width, l)); 4201 break; 4202 } 4203 case DateTime.AM_PM: { // 'p' (am or pm) 4204 // Calendar.AM = 0, Calendar.PM = 1, LocaleElements defines upper 4205 String[] ampm = { "AM", "PM" }; 4206 if (l != null && l != Locale.US) { 4207 DateFormatSymbols dfs = DateFormatSymbols.getInstance(l); 4208 ampm = dfs.getAmPmStrings(); 4209 } 4210 String s = ampm[t.get(Calendar.AM_PM)]; 4211 sb.append(s.toLowerCase(Objects.requireNonNullElse(l, 4212 Locale.getDefault(Locale.Category.FORMAT)))); 4213 break; 4214 } 4215 case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?) 4216 long i = t.getTimeInMillis() / 1000; 4217 Flags flags = Flags.NONE; 4218 sb.append(localizedMagnitude(null, i, flags, width, l)); 4219 break; 4220 } 4221 case DateTime.SECOND: { // 'S' (00 - 60 - leap second) 4222 int i = t.get(Calendar.SECOND); 4223 Flags flags = Flags.ZERO_PAD; 4224 sb.append(localizedMagnitude(null, i, flags, 2, l)); 4225 break; 4226 } 4227 case DateTime.ZONE_NUMERIC: { // 'z' ({-|+}####) - ls minus? 4228 int i = t.get(Calendar.ZONE_OFFSET) + t.get(Calendar.DST_OFFSET); 4229 boolean neg = i < 0; 4230 sb.append(neg ? '-' : '+'); 4231 if (neg) 4232 i = -i; 4233 int min = i / 60000; 4234 // combine minute and hour into a single integer 4235 int offset = (min / 60) * 100 + (min % 60); 4236 Flags flags = Flags.ZERO_PAD; 4237 4238 sb.append(localizedMagnitude(null, offset, flags, 4, l)); 4239 break; 4240 } 4241 case DateTime.ZONE: { // 'Z' (symbol) 4242 TimeZone tz = t.getTimeZone(); 4243 sb.append(tz.getDisplayName((t.get(Calendar.DST_OFFSET) != 0), 4244 TimeZone.SHORT, 4245 Objects.requireNonNullElse(l, Locale.US))); 4246 break; 4247 } 4248 4249 // Date 4250 case DateTime.NAME_OF_DAY_ABBREV: // 'a' 4251 case DateTime.NAME_OF_DAY: { // 'A' 4252 int i = t.get(Calendar.DAY_OF_WEEK); 4253 Locale lt = Objects.requireNonNullElse(l, Locale.US); 4254 DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt); 4255 if (c == DateTime.NAME_OF_DAY) 4256 sb.append(dfs.getWeekdays()[i]); 4257 else 4258 sb.append(dfs.getShortWeekdays()[i]); 4259 break; 4260 } 4261 case DateTime.NAME_OF_MONTH_ABBREV: // 'b' 4262 case DateTime.NAME_OF_MONTH_ABBREV_X: // 'h' -- same b 4263 case DateTime.NAME_OF_MONTH: { // 'B' 4264 int i = t.get(Calendar.MONTH); 4265 Locale lt = Objects.requireNonNullElse(l, Locale.US); 4266 DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt); 4267 if (c == DateTime.NAME_OF_MONTH) 4268 sb.append(dfs.getMonths()[i]); 4269 else 4270 sb.append(dfs.getShortMonths()[i]); 4271 break; 4272 } 4273 case DateTime.CENTURY: // 'C' (00 - 99) 4274 case DateTime.YEAR_2: // 'y' (00 - 99) 4275 case DateTime.YEAR_4: { // 'Y' (0000 - 9999) 4276 int i = t.get(Calendar.YEAR); 4277 int size = 2; 4278 switch (c) { 4279 case DateTime.CENTURY -> i /= 100; 4280 case DateTime.YEAR_2 -> i %= 100; 4281 case DateTime.YEAR_4 -> size = 4; 4282 } 4283 Flags flags = Flags.ZERO_PAD; 4284 sb.append(localizedMagnitude(null, i, flags, size, l)); 4285 break; 4286 } 4287 case DateTime.DAY_OF_MONTH_0: // 'd' (01 - 31) 4288 case DateTime.DAY_OF_MONTH: { // 'e' (1 - 31) -- like d 4289 int i = t.get(Calendar.DATE); 4290 Flags flags = (c == DateTime.DAY_OF_MONTH_0 4291 ? Flags.ZERO_PAD 4292 : Flags.NONE); 4293 sb.append(localizedMagnitude(null, i, flags, 2, l)); 4294 break; 4295 } 4296 case DateTime.DAY_OF_YEAR: { // 'j' (001 - 366) 4297 int i = t.get(Calendar.DAY_OF_YEAR); 4298 Flags flags = Flags.ZERO_PAD; 4299 sb.append(localizedMagnitude(null, i, flags, 3, l)); 4300 break; 4301 } 4302 case DateTime.MONTH: { // 'm' (01 - 12) 4303 int i = t.get(Calendar.MONTH) + 1; 4304 Flags flags = Flags.ZERO_PAD; 4305 sb.append(localizedMagnitude(null, i, flags, 2, l)); 4306 break; 4307 } 4308 4309 // Composites 4310 case DateTime.TIME: // 'T' (24 hour hh:mm:ss - %tH:%tM:%tS) 4311 case DateTime.TIME_24_HOUR: { // 'R' (hh:mm same as %H:%M) 4312 char sep = ':'; 4313 print(sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep); 4314 print(sb, t, DateTime.MINUTE, l); 4315 if (c == DateTime.TIME) { 4316 sb.append(sep); 4317 print(sb, t, DateTime.SECOND, l); 4318 } 4319 break; 4320 } 4321 case DateTime.TIME_12_HOUR: { // 'r' (hh:mm:ss [AP]M) 4322 char sep = ':'; 4323 print(sb, t, DateTime.HOUR_0, l).append(sep); 4324 print(sb, t, DateTime.MINUTE, l).append(sep); 4325 print(sb, t, DateTime.SECOND, l).append(' '); 4326 // this may be in wrong place for some locales 4327 StringBuilder tsb = new StringBuilder(); 4328 print(tsb, t, DateTime.AM_PM, l); 4329 4330 sb.append(toUpperCaseWithLocale(tsb.toString(), l)); 4331 break; 4332 } 4333 case DateTime.DATE_TIME: { // 'c' (Sat Nov 04 12:02:33 EST 1999) 4334 char sep = ' '; 4335 print(sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep); 4336 print(sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep); 4337 print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep); 4338 print(sb, t, DateTime.TIME, l).append(sep); 4339 print(sb, t, DateTime.ZONE, l).append(sep); 4340 print(sb, t, DateTime.YEAR_4, l); 4341 break; 4342 } 4343 case DateTime.DATE: { // 'D' (mm/dd/yy) 4344 char sep = '/'; 4345 print(sb, t, DateTime.MONTH, l).append(sep); 4346 print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep); 4347 print(sb, t, DateTime.YEAR_2, l); 4348 break; 4349 } 4350 case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d) 4351 char sep = '-'; 4352 print(sb, t, DateTime.YEAR_4, l).append(sep); 4353 print(sb, t, DateTime.MONTH, l).append(sep); 4354 print(sb, t, DateTime.DAY_OF_MONTH_0, l); 4355 break; 4356 } 4357 default: 4358 assert false; 4359 } 4360 return sb; 4361 } 4362 4363 private void print(TemporalAccessor t, char c, Locale l) throws IOException { 4364 StringBuilder sb = new StringBuilder(); 4365 print(sb, t, c, l); 4366 // justify based on width 4367 if (f.contains(Flags.UPPERCASE)) { 4368 appendJustified(a, toUpperCaseWithLocale(sb.toString(), l)); 4369 } else { 4370 appendJustified(a, sb); 4371 } 4372 } 4373 4374 private Appendable print(StringBuilder sb, TemporalAccessor t, char c, 4375 Locale l) throws IOException { 4376 if (sb == null) 4377 sb = new StringBuilder(); 4378 try { 4379 switch (c) { 4380 case DateTime.HOUR_OF_DAY_0: { // 'H' (00 - 23) 4381 int i = t.get(ChronoField.HOUR_OF_DAY); 4382 sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l)); 4383 break; 4384 } 4385 case DateTime.HOUR_OF_DAY: { // 'k' (0 - 23) -- like H 4386 int i = t.get(ChronoField.HOUR_OF_DAY); 4387 sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l)); 4388 break; 4389 } 4390 case DateTime.HOUR_0: { // 'I' (01 - 12) 4391 int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM); 4392 sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l)); 4393 break; 4394 } 4395 case DateTime.HOUR: { // 'l' (1 - 12) -- like I 4396 int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM); 4397 sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l)); 4398 break; 4399 } 4400 case DateTime.MINUTE: { // 'M' (00 - 59) 4401 int i = t.get(ChronoField.MINUTE_OF_HOUR); 4402 Flags flags = Flags.ZERO_PAD; 4403 sb.append(localizedMagnitude(null, i, flags, 2, l)); 4404 break; 4405 } 4406 case DateTime.NANOSECOND: { // 'N' (000000000 - 999999999) 4407 int i; 4408 try { 4409 i = t.get(ChronoField.NANO_OF_SECOND); 4410 } catch (UnsupportedTemporalTypeException u) { 4411 i = t.get(ChronoField.MILLI_OF_SECOND) * 1000000; 4412 } 4413 Flags flags = Flags.ZERO_PAD; 4414 sb.append(localizedMagnitude(null, i, flags, 9, l)); 4415 break; 4416 } 4417 case DateTime.MILLISECOND: { // 'L' (000 - 999) 4418 int i = t.get(ChronoField.MILLI_OF_SECOND); 4419 Flags flags = Flags.ZERO_PAD; 4420 sb.append(localizedMagnitude(null, i, flags, 3, l)); 4421 break; 4422 } 4423 case DateTime.MILLISECOND_SINCE_EPOCH: { // 'Q' (0 - 99...?) 4424 long i = t.getLong(ChronoField.INSTANT_SECONDS) * 1000L + 4425 t.getLong(ChronoField.MILLI_OF_SECOND); 4426 Flags flags = Flags.NONE; 4427 sb.append(localizedMagnitude(null, i, flags, width, l)); 4428 break; 4429 } 4430 case DateTime.AM_PM: { // 'p' (am or pm) 4431 // Calendar.AM = 0, Calendar.PM = 1, LocaleElements defines upper 4432 String[] ampm = { "AM", "PM" }; 4433 if (l != null && l != Locale.US) { 4434 DateFormatSymbols dfs = DateFormatSymbols.getInstance(l); 4435 ampm = dfs.getAmPmStrings(); 4436 } 4437 String s = ampm[t.get(ChronoField.AMPM_OF_DAY)]; 4438 sb.append(s.toLowerCase(Objects.requireNonNullElse(l, 4439 Locale.getDefault(Locale.Category.FORMAT)))); 4440 break; 4441 } 4442 case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?) 4443 long i = t.getLong(ChronoField.INSTANT_SECONDS); 4444 Flags flags = Flags.NONE; 4445 sb.append(localizedMagnitude(null, i, flags, width, l)); 4446 break; 4447 } 4448 case DateTime.SECOND: { // 'S' (00 - 60 - leap second) 4449 int i = t.get(ChronoField.SECOND_OF_MINUTE); 4450 Flags flags = Flags.ZERO_PAD; 4451 sb.append(localizedMagnitude(null, i, flags, 2, l)); 4452 break; 4453 } 4454 case DateTime.ZONE_NUMERIC: { // 'z' ({-|+}####) - ls minus? 4455 int i = t.get(ChronoField.OFFSET_SECONDS); 4456 boolean neg = i < 0; 4457 sb.append(neg ? '-' : '+'); 4458 if (neg) 4459 i = -i; 4460 int min = i / 60; 4461 // combine minute and hour into a single integer 4462 int offset = (min / 60) * 100 + (min % 60); 4463 Flags flags = Flags.ZERO_PAD; 4464 sb.append(localizedMagnitude(null, offset, flags, 4, l)); 4465 break; 4466 } 4467 case DateTime.ZONE: { // 'Z' (symbol) 4468 ZoneId zid = t.query(TemporalQueries.zone()); 4469 if (zid == null) { 4470 throw new IllegalFormatConversionException(c, t.getClass()); 4471 } 4472 if (!(zid instanceof ZoneOffset) && 4473 t.isSupported(ChronoField.INSTANT_SECONDS)) { 4474 Instant instant = Instant.from(t); 4475 sb.append(TimeZone.getTimeZone(zid.getId()) 4476 .getDisplayName(zid.getRules().isDaylightSavings(instant), 4477 TimeZone.SHORT, 4478 Objects.requireNonNullElse(l, Locale.US))); 4479 break; 4480 } 4481 sb.append(zid.getId()); 4482 break; 4483 } 4484 // Date 4485 case DateTime.NAME_OF_DAY_ABBREV: // 'a' 4486 case DateTime.NAME_OF_DAY: { // 'A' 4487 int i = t.get(ChronoField.DAY_OF_WEEK) % 7 + 1; 4488 Locale lt = Objects.requireNonNullElse(l, Locale.US); 4489 DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt); 4490 if (c == DateTime.NAME_OF_DAY) 4491 sb.append(dfs.getWeekdays()[i]); 4492 else 4493 sb.append(dfs.getShortWeekdays()[i]); 4494 break; 4495 } 4496 case DateTime.NAME_OF_MONTH_ABBREV: // 'b' 4497 case DateTime.NAME_OF_MONTH_ABBREV_X: // 'h' -- same b 4498 case DateTime.NAME_OF_MONTH: { // 'B' 4499 int i = t.get(ChronoField.MONTH_OF_YEAR) - 1; 4500 Locale lt = Objects.requireNonNullElse(l, Locale.US); 4501 DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt); 4502 if (c == DateTime.NAME_OF_MONTH) 4503 sb.append(dfs.getMonths()[i]); 4504 else 4505 sb.append(dfs.getShortMonths()[i]); 4506 break; 4507 } 4508 case DateTime.CENTURY: // 'C' (00 - 99) 4509 case DateTime.YEAR_2: // 'y' (00 - 99) 4510 case DateTime.YEAR_4: { // 'Y' (0000 - 9999) 4511 int i = t.get(ChronoField.YEAR_OF_ERA); 4512 int size = 2; 4513 switch (c) { 4514 case DateTime.CENTURY -> i /= 100; 4515 case DateTime.YEAR_2 -> i %= 100; 4516 case DateTime.YEAR_4 -> size = 4; 4517 } 4518 Flags flags = Flags.ZERO_PAD; 4519 sb.append(localizedMagnitude(null, i, flags, size, l)); 4520 break; 4521 } 4522 case DateTime.DAY_OF_MONTH_0: // 'd' (01 - 31) 4523 case DateTime.DAY_OF_MONTH: { // 'e' (1 - 31) -- like d 4524 int i = t.get(ChronoField.DAY_OF_MONTH); 4525 Flags flags = (c == DateTime.DAY_OF_MONTH_0 4526 ? Flags.ZERO_PAD 4527 : Flags.NONE); 4528 sb.append(localizedMagnitude(null, i, flags, 2, l)); 4529 break; 4530 } 4531 case DateTime.DAY_OF_YEAR: { // 'j' (001 - 366) 4532 int i = t.get(ChronoField.DAY_OF_YEAR); 4533 Flags flags = Flags.ZERO_PAD; 4534 sb.append(localizedMagnitude(null, i, flags, 3, l)); 4535 break; 4536 } 4537 case DateTime.MONTH: { // 'm' (01 - 12) 4538 int i = t.get(ChronoField.MONTH_OF_YEAR); 4539 Flags flags = Flags.ZERO_PAD; 4540 sb.append(localizedMagnitude(null, i, flags, 2, l)); 4541 break; 4542 } 4543 4544 // Composites 4545 case DateTime.TIME: // 'T' (24 hour hh:mm:ss - %tH:%tM:%tS) 4546 case DateTime.TIME_24_HOUR: { // 'R' (hh:mm same as %H:%M) 4547 char sep = ':'; 4548 print(sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep); 4549 print(sb, t, DateTime.MINUTE, l); 4550 if (c == DateTime.TIME) { 4551 sb.append(sep); 4552 print(sb, t, DateTime.SECOND, l); 4553 } 4554 break; 4555 } 4556 case DateTime.TIME_12_HOUR: { // 'r' (hh:mm:ss [AP]M) 4557 char sep = ':'; 4558 print(sb, t, DateTime.HOUR_0, l).append(sep); 4559 print(sb, t, DateTime.MINUTE, l).append(sep); 4560 print(sb, t, DateTime.SECOND, l).append(' '); 4561 // this may be in wrong place for some locales 4562 StringBuilder tsb = new StringBuilder(); 4563 print(tsb, t, DateTime.AM_PM, l); 4564 sb.append(toUpperCaseWithLocale(tsb.toString(), l)); 4565 break; 4566 } 4567 case DateTime.DATE_TIME: { // 'c' (Sat Nov 04 12:02:33 EST 1999) 4568 char sep = ' '; 4569 print(sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep); 4570 print(sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep); 4571 print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep); 4572 print(sb, t, DateTime.TIME, l).append(sep); 4573 print(sb, t, DateTime.ZONE, l).append(sep); 4574 print(sb, t, DateTime.YEAR_4, l); 4575 break; 4576 } 4577 case DateTime.DATE: { // 'D' (mm/dd/yy) 4578 char sep = '/'; 4579 print(sb, t, DateTime.MONTH, l).append(sep); 4580 print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep); 4581 print(sb, t, DateTime.YEAR_2, l); 4582 break; 4583 } 4584 case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d) 4585 char sep = '-'; 4586 print(sb, t, DateTime.YEAR_4, l).append(sep); 4587 print(sb, t, DateTime.MONTH, l).append(sep); 4588 print(sb, t, DateTime.DAY_OF_MONTH_0, l); 4589 break; 4590 } 4591 default: 4592 assert false; 4593 } 4594 } catch (DateTimeException x) { 4595 throw new IllegalFormatConversionException(c, t.getClass()); 4596 } 4597 return sb; 4598 } 4599 4600 // -- Methods to support throwing exceptions -- 4601 4602 private void failMismatch(Flags f, char c) { 4603 String fs = f.toString(); 4604 throw new FormatFlagsConversionMismatchException(fs, c); 4605 } 4606 4607 private void failConversion(char c, Object arg) { 4608 throw new IllegalFormatConversionException(c, arg.getClass()); 4609 } 4610 4611 private char getZero(Locale l) { 4612 if ((l != null) && !l.equals(locale())) { 4613 // Android-changed: Improve the performance by 10x http://b/197788756 4614 // Unclear if this mapping is needed but inherited from DecimalFormatSymbols 4615 l = LocaleData.mapInvalidAndNullLocales(l); 4616 DecimalFormatData decimalFormatData = DecimalFormatData.getInstance(l); 4617 return decimalFormatData.getZeroDigit(); 4618 // DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l); 4619 // return dfs.getZeroDigit(); 4620 } 4621 return zero(); 4622 } 4623 4624 private StringBuilder localizedMagnitude(StringBuilder sb, 4625 long value, Flags f, int width, Locale l) { 4626 return localizedMagnitude(sb, Long.toString(value, 10), 0, f, width, l); 4627 } 4628 4629 private StringBuilder localizedMagnitude(StringBuilder sb, 4630 CharSequence value, final int offset, Flags f, int width, 4631 Locale l) { 4632 if (sb == null) { 4633 sb = new StringBuilder(); 4634 } 4635 int begin = sb.length(); 4636 4637 char zero = getZero(l); 4638 4639 // determine localized grouping separator and size 4640 char grpSep = '\0'; 4641 int grpSize = -1; 4642 char decSep = '\0'; 4643 4644 int len = value.length(); 4645 int dot = len; 4646 for (int j = offset; j < len; j++) { 4647 if (value.charAt(j) == '.') { 4648 dot = j; 4649 break; 4650 } 4651 } 4652 4653 if (dot < len) { 4654 if (l == null || l.equals(Locale.US)) { 4655 decSep = '.'; 4656 } else { 4657 DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l); 4658 decSep = dfs.getDecimalSeparator(); 4659 } 4660 } 4661 4662 if (f.contains(Flags.GROUP)) { 4663 if (l == null || l.equals(Locale.US)) { 4664 grpSep = ','; 4665 grpSize = 3; 4666 } else { 4667 DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l); 4668 grpSep = dfs.getGroupingSeparator(); 4669 // Android-removed: DecimalFormat is always returned. 4670 /* 4671 DecimalFormat df = null; 4672 NumberFormat nf = NumberFormat.getNumberInstance(l); 4673 if (nf instanceof DecimalFormat) { 4674 df = (DecimalFormat) nf; 4675 } else { 4676 4677 // Use DecimalFormat constructor to obtain the instance, 4678 // in case NumberFormat.getNumberInstance(l) 4679 // returns instance other than DecimalFormat 4680 LocaleProviderAdapter adapter = LocaleProviderAdapter 4681 .getAdapter(NumberFormatProvider.class, l); 4682 if (!(adapter instanceof ResourceBundleBasedAdapter)) { 4683 adapter = LocaleProviderAdapter.getResourceBundleBased(); 4684 } 4685 String[] all = adapter.getLocaleResources(l) 4686 .getNumberPatterns(); 4687 df = new DecimalFormat(all[0], dfs); 4688 } 4689 */ 4690 DecimalFormat df = (DecimalFormat) NumberFormat.getIntegerInstance(l); 4691 grpSize = df.getGroupingSize(); 4692 4693 if (!df.isGroupingUsed() || grpSize == 0) { 4694 grpSep = '\0'; 4695 } 4696 } 4697 } 4698 4699 // localize the digits inserting group separators as necessary 4700 for (int j = offset; j < len; j++) { 4701 if (j == dot) { 4702 sb.append(decSep); 4703 // no more group separators after the decimal separator 4704 grpSep = '\0'; 4705 continue; 4706 } 4707 4708 char c = value.charAt(j); 4709 sb.append((char) ((c - '0') + zero)); 4710 if (grpSep != '\0' && j != dot - 1 && ((dot - j) % grpSize == 1)) { 4711 sb.append(grpSep); 4712 } 4713 } 4714 4715 // apply zero padding 4716 if (width != -1 && f.contains(Flags.ZERO_PAD)) { 4717 for (int k = sb.length(); k < width; k++) { 4718 sb.insert(begin, zero); 4719 } 4720 } 4721 4722 return sb; 4723 } 4724 4725 // Specialized localization of exponents, where the source value can only 4726 // contain characters '0' through '9', starting at index offset, and no 4727 // group separators is added for any locale. 4728 private void localizedMagnitudeExp(StringBuilder sb, char[] value, 4729 final int offset, Locale l) { 4730 char zero = getZero(l); 4731 4732 int len = value.length; 4733 for (int j = offset; j < len; j++) { 4734 char c = value[j]; 4735 sb.append((char) ((c - '0') + zero)); 4736 } 4737 } 4738 } 4739 4740 private static class Flags { 4741 private int flags; 4742 4743 static final Flags NONE = new Flags(0); // '' 4744 4745 // duplicate declarations from Formattable.java 4746 static final Flags LEFT_JUSTIFY = new Flags(1<<0); // '-' 4747 static final Flags UPPERCASE = new Flags(1<<1); // '^' 4748 static final Flags ALTERNATE = new Flags(1<<2); // '#' 4749 4750 // numerics 4751 static final Flags PLUS = new Flags(1<<3); // '+' 4752 static final Flags LEADING_SPACE = new Flags(1<<4); // ' ' 4753 static final Flags ZERO_PAD = new Flags(1<<5); // '0' 4754 static final Flags GROUP = new Flags(1<<6); // ',' 4755 static final Flags PARENTHESES = new Flags(1<<7); // '(' 4756 4757 // indexing 4758 static final Flags PREVIOUS = new Flags(1<<8); // '<' 4759 4760 private Flags(int f) { 4761 flags = f; 4762 } 4763 4764 public int valueOf() { 4765 return flags; 4766 } 4767 4768 public boolean contains(Flags f) { 4769 return (flags & f.valueOf()) == f.valueOf(); 4770 } 4771 4772 public Flags dup() { 4773 return new Flags(flags); 4774 } 4775 4776 private Flags add(Flags f) { 4777 flags |= f.valueOf(); 4778 return this; 4779 } 4780 4781 public Flags remove(Flags f) { 4782 flags &= ~f.valueOf(); 4783 return this; 4784 } 4785 4786 public static Flags parse(String s, int start, int end) { 4787 Flags f = new Flags(0); 4788 for (int i = start; i < end; i++) { 4789 char c = s.charAt(i); 4790 Flags v = parse(c); 4791 if (f.contains(v)) 4792 throw new DuplicateFormatFlagsException(v.toString()); 4793 f.add(v); 4794 } 4795 return f; 4796 } 4797 4798 // parse those flags which may be provided by users 4799 private static Flags parse(char c) { 4800 return switch (c) { 4801 case '-' -> LEFT_JUSTIFY; 4802 case '#' -> ALTERNATE; 4803 case '+' -> PLUS; 4804 case ' ' -> LEADING_SPACE; 4805 case '0' -> ZERO_PAD; 4806 case ',' -> GROUP; 4807 case '(' -> PARENTHESES; 4808 case '<' -> PREVIOUS; 4809 default -> throw new UnknownFormatFlagsException(String.valueOf(c)); 4810 }; 4811 } 4812 4813 // Returns a string representation of the current {@code Flags}. 4814 public static String toString(Flags f) { 4815 return f.toString(); 4816 } 4817 4818 public String toString() { 4819 StringBuilder sb = new StringBuilder(); 4820 if (contains(LEFT_JUSTIFY)) sb.append('-'); 4821 if (contains(UPPERCASE)) sb.append('^'); 4822 if (contains(ALTERNATE)) sb.append('#'); 4823 if (contains(PLUS)) sb.append('+'); 4824 if (contains(LEADING_SPACE)) sb.append(' '); 4825 if (contains(ZERO_PAD)) sb.append('0'); 4826 if (contains(GROUP)) sb.append(','); 4827 if (contains(PARENTHESES)) sb.append('('); 4828 if (contains(PREVIOUS)) sb.append('<'); 4829 return sb.toString(); 4830 } 4831 } 4832 4833 private static class Conversion { 4834 // Byte, Short, Integer, Long, BigInteger 4835 // (and associated primitives due to autoboxing) 4836 static final char DECIMAL_INTEGER = 'd'; 4837 static final char OCTAL_INTEGER = 'o'; 4838 static final char HEXADECIMAL_INTEGER = 'x'; 4839 static final char HEXADECIMAL_INTEGER_UPPER = 'X'; 4840 4841 // Float, Double, BigDecimal 4842 // (and associated primitives due to autoboxing) 4843 static final char SCIENTIFIC = 'e'; 4844 static final char SCIENTIFIC_UPPER = 'E'; 4845 static final char GENERAL = 'g'; 4846 static final char GENERAL_UPPER = 'G'; 4847 static final char DECIMAL_FLOAT = 'f'; 4848 static final char HEXADECIMAL_FLOAT = 'a'; 4849 static final char HEXADECIMAL_FLOAT_UPPER = 'A'; 4850 4851 // Character, Byte, Short, Integer 4852 // (and associated primitives due to autoboxing) 4853 static final char CHARACTER = 'c'; 4854 static final char CHARACTER_UPPER = 'C'; 4855 4856 // java.util.Date, java.util.Calendar, long 4857 static final char DATE_TIME = 't'; 4858 static final char DATE_TIME_UPPER = 'T'; 4859 4860 // if (arg.TYPE != boolean) return boolean 4861 // if (arg != null) return true; else return false; 4862 static final char BOOLEAN = 'b'; 4863 static final char BOOLEAN_UPPER = 'B'; 4864 // if (arg instanceof Formattable) arg.formatTo() 4865 // else arg.toString(); 4866 static final char STRING = 's'; 4867 static final char STRING_UPPER = 'S'; 4868 // arg.hashCode() 4869 static final char HASHCODE = 'h'; 4870 static final char HASHCODE_UPPER = 'H'; 4871 4872 static final char LINE_SEPARATOR = 'n'; 4873 static final char PERCENT_SIGN = '%'; 4874 4875 static boolean isValid(char c) { 4876 return switch (c) { 4877 case BOOLEAN, 4878 BOOLEAN_UPPER, 4879 STRING, 4880 STRING_UPPER, 4881 HASHCODE, 4882 HASHCODE_UPPER, 4883 CHARACTER, 4884 CHARACTER_UPPER, 4885 DECIMAL_INTEGER, 4886 OCTAL_INTEGER, 4887 HEXADECIMAL_INTEGER, 4888 HEXADECIMAL_INTEGER_UPPER, 4889 SCIENTIFIC, 4890 SCIENTIFIC_UPPER, 4891 GENERAL, 4892 GENERAL_UPPER, 4893 DECIMAL_FLOAT, 4894 HEXADECIMAL_FLOAT, 4895 HEXADECIMAL_FLOAT_UPPER, 4896 LINE_SEPARATOR, 4897 PERCENT_SIGN -> true; 4898 default -> false; 4899 }; 4900 } 4901 4902 // Returns true iff the Conversion is applicable to all objects. 4903 static boolean isGeneral(char c) { 4904 return switch (c) { 4905 case BOOLEAN, 4906 BOOLEAN_UPPER, 4907 STRING, 4908 STRING_UPPER, 4909 HASHCODE, 4910 HASHCODE_UPPER -> true; 4911 default -> false; 4912 }; 4913 } 4914 4915 // Returns true iff the Conversion is applicable to character. 4916 static boolean isCharacter(char c) { 4917 return switch (c) { 4918 case CHARACTER, 4919 CHARACTER_UPPER -> true; 4920 default -> false; 4921 }; 4922 } 4923 4924 // Returns true iff the Conversion is an integer type. 4925 static boolean isInteger(char c) { 4926 return switch (c) { 4927 case DECIMAL_INTEGER, 4928 OCTAL_INTEGER, 4929 HEXADECIMAL_INTEGER, 4930 HEXADECIMAL_INTEGER_UPPER -> true; 4931 default -> false; 4932 }; 4933 } 4934 4935 // Returns true iff the Conversion is a floating-point type. 4936 static boolean isFloat(char c) { 4937 return switch (c) { 4938 case SCIENTIFIC, 4939 SCIENTIFIC_UPPER, 4940 GENERAL, 4941 GENERAL_UPPER, 4942 DECIMAL_FLOAT, 4943 HEXADECIMAL_FLOAT, 4944 HEXADECIMAL_FLOAT_UPPER -> true; 4945 default -> false; 4946 }; 4947 } 4948 4949 // Returns true iff the Conversion does not require an argument 4950 static boolean isText(char c) { 4951 return switch (c) { 4952 case LINE_SEPARATOR, PERCENT_SIGN -> true; 4953 default -> false; 4954 }; 4955 } 4956 } 4957 4958 private static class DateTime { 4959 static final char HOUR_OF_DAY_0 = 'H'; // (00 - 23) 4960 static final char HOUR_0 = 'I'; // (01 - 12) 4961 static final char HOUR_OF_DAY = 'k'; // (0 - 23) -- like H 4962 static final char HOUR = 'l'; // (1 - 12) -- like I 4963 static final char MINUTE = 'M'; // (00 - 59) 4964 static final char NANOSECOND = 'N'; // (000000000 - 999999999) 4965 static final char MILLISECOND = 'L'; // jdk, not in gnu (000 - 999) 4966 static final char MILLISECOND_SINCE_EPOCH = 'Q'; // (0 - 99...?) 4967 static final char AM_PM = 'p'; // (am or pm) 4968 static final char SECONDS_SINCE_EPOCH = 's'; // (0 - 99...?) 4969 static final char SECOND = 'S'; // (00 - 60 - leap second) 4970 static final char TIME = 'T'; // (24 hour hh:mm:ss) 4971 static final char ZONE_NUMERIC = 'z'; // (-1200 - +1200) - ls minus? 4972 static final char ZONE = 'Z'; // (symbol) 4973 4974 // Date 4975 static final char NAME_OF_DAY_ABBREV = 'a'; // 'a' 4976 static final char NAME_OF_DAY = 'A'; // 'A' 4977 static final char NAME_OF_MONTH_ABBREV = 'b'; // 'b' 4978 static final char NAME_OF_MONTH = 'B'; // 'B' 4979 static final char CENTURY = 'C'; // (00 - 99) 4980 static final char DAY_OF_MONTH_0 = 'd'; // (01 - 31) 4981 static final char DAY_OF_MONTH = 'e'; // (1 - 31) -- like d 4982 static final char NAME_OF_MONTH_ABBREV_X = 'h'; // -- same b 4983 static final char DAY_OF_YEAR = 'j'; // (001 - 366) 4984 static final char MONTH = 'm'; // (01 - 12) 4985 static final char YEAR_2 = 'y'; // (00 - 99) 4986 static final char YEAR_4 = 'Y'; // (0000 - 9999) 4987 4988 // Composites 4989 static final char TIME_12_HOUR = 'r'; // (hh:mm:ss [AP]M) 4990 static final char TIME_24_HOUR = 'R'; // (hh:mm same as %H:%M) 4991 static final char DATE_TIME = 'c'; 4992 // (Sat Nov 04 12:02:33 EST 1999) 4993 static final char DATE = 'D'; // (mm/dd/yy) 4994 static final char ISO_STANDARD_DATE = 'F'; // (%Y-%m-%d) 4995 4996 static boolean isValid(char c) { 4997 return switch (c) { 4998 case HOUR_OF_DAY_0, HOUR_0, HOUR_OF_DAY, HOUR, MINUTE, NANOSECOND, MILLISECOND, MILLISECOND_SINCE_EPOCH, 4999 AM_PM, SECONDS_SINCE_EPOCH, SECOND, TIME, ZONE_NUMERIC, ZONE -> true; 5000 // Date 5001 case NAME_OF_DAY_ABBREV, NAME_OF_DAY, NAME_OF_MONTH_ABBREV, NAME_OF_MONTH, CENTURY, DAY_OF_MONTH_0, 5002 DAY_OF_MONTH, NAME_OF_MONTH_ABBREV_X, DAY_OF_YEAR, MONTH, YEAR_2, YEAR_4 -> true; 5003 // Composites 5004 case TIME_12_HOUR, TIME_24_HOUR, DATE_TIME, DATE, ISO_STANDARD_DATE -> true; 5005 default -> false; 5006 }; 5007 } 5008 } 5009 } 5010