Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/java/util/Formatter.java
41152 views
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
* // -&gt; " 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
* // -&gt; "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
* // -&gt; "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
* // -&gt; "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
* // -&gt; "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
* // -&gt; 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>'&#92;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>'&#92;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&nbsp;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&nbsp;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"> '&nbsp;&nbsp;' <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>'&#92;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 %&lt;te,%&lt;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;u002d'</code>
803
* <td> Left justifies the output. Spaces (<code>'&#92;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>'&#92;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>'&nbsp;&nbsp;'</code> (<code>'&#92;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>'&#92;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>'&#92;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&nbsp;-&nbsp;</i> {@code '0'}
901
* <i>&nbsp;+&nbsp;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>'&#92;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>'&#92;u0028'</code>) is prepended and a {@code ')'}
922
* (<code>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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 '+'}, '&nbsp;&nbsp;', 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>'&#92;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>'&nbsp;&nbsp;'</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>'&#92;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>'&#92;u0061'</code> - <code>'&#92;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>'&#92;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>'&nbsp;&nbsp;'</code> flags are given
1039
* then an {@link IllegalFormatFlagsException} will be thrown.
1040
*
1041
* <tr><th scope="row" style="vertical-align:top"> <code>'&nbsp;&nbsp;'</code>
1042
* <td style="vertical-align:top"> <code>'&#92;u0020'</code>
1043
* <td> Requires the output to include a single extra space
1044
* (<code>'&#92;u0020'</code>) for non-negative values.
1045
*
1046
* <p> If both the {@code '+'} and <code>'&nbsp;&nbsp;'</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>'&#92;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>'&#92;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>'&#92;u0028'</code>
1069
* <td> Requires the output to prepend a {@code '('}
1070
* (<code>'&#92;u0028'</code>) and append a {@code ')'}
1071
* (<code>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;u0061'</code> - <code>'&#92;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>'&#92;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
* &lt;= <i>m</i> &lt; 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 &lt;= <i>a</i> &lt; 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>'&#92;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>'&#92;u0045'</code>
1260
* <td> The upper-case variant of {@code 'e'}. The exponent symbol
1261
* will be {@code 'E'} (<code>'&#92;u0045'</code>).
1262
*
1263
* <tr><th scope="row" style="vertical-align:top"> {@code 'g'}
1264
* <td style="vertical-align:top"> <code>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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,&nbsp;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>'&#92;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>'&#92;u0078'</code>) and {@code 'p'}
1382
* (<code>'&#92;u0070'</code> and all hexadecimal digits {@code 'a'} -
1383
* {@code 'f'} (<code>'&#92;u0061'</code> - <code>'&#92;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>'&#92;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>'&#92;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
* &lt;= <i>m</i> &lt; 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 &lt;= <i>a</i> &lt; 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>'&#92;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>'&#92;u0045'</code>
1491
* <td> The upper-case variant of {@code 'e'}. The exponent symbol
1492
* will be {@code 'E'} (<code>'&#92;u0045'</code>).
1493
*
1494
* <tr><th scope="row" style="vertical-align:top"> {@code 'g'}
1495
* <td style="vertical-align:top"> <code>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;u007a'</code>
1654
* <td> <a href="http://www.ietf.org/rfc/rfc0822.txt">RFC&nbsp;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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>'&#92;u0046'</code>
1788
* <td> <a href="http://www.w3.org/TR/NOTE-datetime">ISO&nbsp;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>'&#92;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>'&#92;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>'&#92;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>'&#92;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
* // -&gt; "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>'&#92;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 %&lt;s %&lt;s", "a", "b", "c", "d")
1888
* // -&gt; "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
* // -&gt; "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 %&lt;s %s", "a", "b", "c", "d")
1910
* // -&gt; "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
*/
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
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 */
1965
private Formatter(Locale l, Appendable a) {
1966
this.a = a;
1967
this.l = l;
1968
}
1969
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
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
*/
2442
public Formatter(OutputStream os, Charset charset, Locale l) {
2443
this(l, new BufferedWriter(new OutputStreamWriter(os, charset)));
2444
}
2445
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
*/
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
*/
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
* // -&gt; 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
*/
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
*/
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
*/
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
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
*/
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
*/
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
*/
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
*/
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 {
2758
int index();
2759
void print(Object arg, Locale l) throws IOException;
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;
2767
FixedString(String s, int start, int end) {
2768
this.s = s;
2769
this.start = start;
2770
this.end = end;
2771
}
2772
public int index() { return -2; }
2773
public void print(Object arg, Locale l)
2774
throws IOException { a.append(s, start, end); }
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
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
2816
public int index() {
2817
return index;
2818
}
2819
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
3086
private String toUpperCaseWithLocale(String s, Locale l) {
3087
return s.toUpperCase(Objects.requireNonNullElse(l,
3088
Locale.getDefault(Locale.Category.FORMAT)));
3089
}
3090
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
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
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
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
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
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
3173
private void checkBadFlags(Flags ... badFlags) {
3174
for (Flags badFlag : badFlags)
3175
if (f.contains(badFlag))
3176
failMismatch(badFlag, c);
3177
}
3178
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
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
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
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
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
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
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
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
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
3861
public BigDecimalLayout(BigInteger intVal, int scale, BigDecimalLayoutForm form) {
3862
layout(intVal, scale, form);
3863
}
3864
3865
public boolean hasDot() {
3866
return dot;
3867
}
3868
3869
public int scale() {
3870
return scale;
3871
}
3872
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.
3879
public StringBuilder exponent() {
3880
return exp;
3881
}
3882
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
4840