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