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.util.regex.Matcher;
51 import java.util.regex.Pattern;
52
53 import sun.misc.DoubleConsts;
54 import sun.misc.FormattedFloatingDecimal;
55
56 /**
57 * An interpreter for printf-style format strings. This class provides support
58 * for layout justification and alignment, common formats for numeric, string,
59 * and date/time data, and locale-specific output. Common Java types such as
60 * {@code byte}, {@link java.math.BigDecimal BigDecimal}, and {@link Calendar}
61 * are supported. Limited formatting customization for arbitrary user types is
62 * provided through the {@link Formattable} interface.
63 *
64 * <p> Formatters are not necessarily safe for multithreaded access. Thread
65 * safety is optional and is the responsibility of users of methods in this
66 * class.
67 *
68 * <p> Formatted printing for the Java language is heavily inspired by C's
69 * {@code printf}. Although the format strings are similar to C, some
70 * customizations have been made to accommodate the Java language and exploit
71 * some of its features. Also, Java formatting is more strict than C's; for
72 * example, if a conversion is incompatible with a flag, an exception will be
237 * Byte}, {@code short}, and {@link Short}. This conversion may also be
238 * applied to the types {@code int} and {@link Integer} when {@link
239 * Character#isValidCodePoint} returns {@code true}
240 *
241 * <li> <b>Numeric</b>
242 *
243 * <ol>
244 *
245 * <li> <b>Integral</b> - may be applied to Java integral types: {@code byte},
246 * {@link Byte}, {@code short}, {@link Short}, {@code int} and {@link
247 * Integer}, {@code long}, {@link Long}, and {@link java.math.BigInteger
248 * BigInteger}
249 *
250 * <li><b>Floating Point</b> - may be applied to Java floating-point types:
251 * {@code float}, {@link Float}, {@code double}, {@link Double}, and {@link
252 * java.math.BigDecimal BigDecimal}
253 *
254 * </ol>
255 *
256 * <li> <b>Date/Time</b> - may be applied to Java types which are capable of
257 * encoding a date or time: {@code long}, {@link Long}, {@link Calendar}, and
258 * {@link Date}.
259 *
260 * <li> <b>Percent</b> - produces a literal {@code '%'}
261 * (<tt>'\u0025'</tt>)
262 *
263 * <li> <b>Line Separator</b> - produces the platform-specific line separator
264 *
265 * </ol>
266 *
267 * <p> The following table summarizes the supported conversions. Conversions
268 * denoted by an upper-case character (i.e. {@code 'B'}, {@code 'H'},
269 * {@code 'S'}, {@code 'C'}, {@code 'X'}, {@code 'E'}, {@code 'G'},
270 * {@code 'A'}, and {@code 'T'}) are the same as those for the corresponding
271 * lower-case conversion characters except that the result is converted to
272 * upper case according to the rules of the prevailing {@link java.util.Locale
273 * Locale}. The result is equivalent to the following invocation of {@link
274 * String#toUpperCase()}
275 *
276 * <pre>
277 * out.toUpperCase() </pre>
278 *
1471 * BigDecimal#toString()}.
1472 *
1473 * </table>
1474 *
1475 * <p> All <a href="#intFlags">flags</a> defined for Byte, Short, Integer, and
1476 * Long apply.
1477 *
1478 * <p> If the {@code '#'} flag is given, then the decimal separator will
1479 * always be present.
1480 *
1481 * <p> The <a href="#floatdFlags">default behavior</a> when no flags are
1482 * given is the same as for Float and Double.
1483 *
1484 * <p> The specification of <a href="#floatDWidth">width</a> and <a
1485 * href="#floatDPrec">precision</a> is the same as defined for Float and
1486 * Double.
1487 *
1488 * <h4><a name="ddt">Date/Time</a></h4>
1489 *
1490 * <p> This conversion may be applied to {@code long}, {@link Long}, {@link
1491 * Calendar}, and {@link Date}.
1492 *
1493 * <table cellpadding=5 summary="DTConv">
1494 *
1495 * <tr><td valign="top"> {@code 't'}
1496 * <td valign="top"> <tt>'\u0074'</tt>
1497 * <td> Prefix for date and time conversion characters.
1498 * <tr><td valign="top"> {@code 'T'}
1499 * <td valign="top"> <tt>'\u0054'</tt>
1500 * <td> The upper-case variant of {@code 't'}.
1501 *
1502 * </table>
1503 *
1504 * <p> The following date and time conversion character suffixes are defined
1505 * for the {@code 't'} and {@code 'T'} conversions. The types are similar to
1506 * but not completely identical to those defined by GNU {@code date} and
1507 * POSIX {@code strftime(3c)}. Additional conversion types are provided to
1508 * access Java-specific functionality (e.g. {@code 'L'} for milliseconds
1509 * within the second).
1510 *
1511 * <p> The following conversion characters are used for formatting times:
2765 print("null");
2766 return;
2767 }
2768 Calendar cal = null;
2769
2770 // Instead of Calendar.setLenient(true), perhaps we should
2771 // wrap the IllegalArgumentException that might be thrown?
2772 if (arg instanceof Long) {
2773 // Note that the following method uses an instance of the
2774 // default time zone (TimeZone.getDefaultRef().
2775 cal = Calendar.getInstance(l == null ? Locale.US : l);
2776 cal.setTimeInMillis((Long)arg);
2777 } else if (arg instanceof Date) {
2778 // Note that the following method uses an instance of the
2779 // default time zone (TimeZone.getDefaultRef().
2780 cal = Calendar.getInstance(l == null ? Locale.US : l);
2781 cal.setTime((Date)arg);
2782 } else if (arg instanceof Calendar) {
2783 cal = (Calendar) ((Calendar)arg).clone();
2784 cal.setLenient(true);
2785 } else {
2786 failConversion(c, arg);
2787 }
2788 // Use the provided locale so that invocations of
2789 // localizedMagnitude() use optimizations for null.
2790 print(cal, c, l);
2791 }
2792
2793 private void printCharacter(Object arg) throws IOException {
2794 if (arg == null) {
2795 print("null");
2796 return;
2797 }
2798 String s = null;
2799 if (arg instanceof Character) {
2800 s = ((Character)arg).toString();
2801 } else if (arg instanceof Byte) {
2802 byte i = ((Byte)arg).byteValue();
2803 if (Character.isValidCodePoint(i))
2804 s = new String(Character.toChars(i));
4015 case DateTime.DATE: { // 'D' (mm/dd/yy)
4016 char sep = '/';
4017 print(sb, t, DateTime.MONTH, l).append(sep);
4018 print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
4019 print(sb, t, DateTime.YEAR_2, l);
4020 break;
4021 }
4022 case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d)
4023 char sep = '-';
4024 print(sb, t, DateTime.YEAR_4, l).append(sep);
4025 print(sb, t, DateTime.MONTH, l).append(sep);
4026 print(sb, t, DateTime.DAY_OF_MONTH_0, l);
4027 break;
4028 }
4029 default:
4030 assert false;
4031 }
4032 return sb;
4033 }
4034
4035 // -- Methods to support throwing exceptions --
4036
4037 private void failMismatch(Flags f, char c) {
4038 String fs = f.toString();
4039 throw new FormatFlagsConversionMismatchException(fs, c);
4040 }
4041
4042 private void failConversion(char c, Object arg) {
4043 throw new IllegalFormatConversionException(c, arg.getClass());
4044 }
4045
4046 private char getZero(Locale l) {
4047 if ((l != null) && !l.equals(locale())) {
4048 DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
4049 return dfs.getZeroDigit();
4050 }
4051 return zero;
4052 }
4053
4054 private StringBuilder
|
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.util.regex.Matcher;
51 import java.util.regex.Pattern;
52
53 import java.time.Clock;
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.Queries;
61 import java.time.temporal.OffsetDate;
62 import java.time.temporal.OffsetDateTime;
63 import java.time.temporal.OffsetTime;
64 import java.time.temporal.ChronoZonedDateTime;
65 import java.time.format.TextStyle;
66 import java.time.zone.ZoneRules;
67
68 import sun.misc.DoubleConsts;
69 import sun.misc.FormattedFloatingDecimal;
70
71 /**
72 * An interpreter for printf-style format strings. This class provides support
73 * for layout justification and alignment, common formats for numeric, string,
74 * and date/time data, and locale-specific output. Common Java types such as
75 * {@code byte}, {@link java.math.BigDecimal BigDecimal}, and {@link Calendar}
76 * are supported. Limited formatting customization for arbitrary user types is
77 * provided through the {@link Formattable} interface.
78 *
79 * <p> Formatters are not necessarily safe for multithreaded access. Thread
80 * safety is optional and is the responsibility of users of methods in this
81 * class.
82 *
83 * <p> Formatted printing for the Java language is heavily inspired by C's
84 * {@code printf}. Although the format strings are similar to C, some
85 * customizations have been made to accommodate the Java language and exploit
86 * some of its features. Also, Java formatting is more strict than C's; for
87 * example, if a conversion is incompatible with a flag, an exception will be
252 * Byte}, {@code short}, and {@link Short}. This conversion may also be
253 * applied to the types {@code int} and {@link Integer} when {@link
254 * Character#isValidCodePoint} returns {@code true}
255 *
256 * <li> <b>Numeric</b>
257 *
258 * <ol>
259 *
260 * <li> <b>Integral</b> - may be applied to Java integral types: {@code byte},
261 * {@link Byte}, {@code short}, {@link Short}, {@code int} and {@link
262 * Integer}, {@code long}, {@link Long}, and {@link java.math.BigInteger
263 * BigInteger}
264 *
265 * <li><b>Floating Point</b> - may be applied to Java floating-point types:
266 * {@code float}, {@link Float}, {@code double}, {@link Double}, and {@link
267 * java.math.BigDecimal BigDecimal}
268 *
269 * </ol>
270 *
271 * <li> <b>Date/Time</b> - may be applied to Java types which are capable of
272 * encoding a date or time: {@code long}, {@link Long}, {@link Calendar},
273 * {@link Date} and {@link TemporalAccessor TemporalAccessor}
274 *
275 * <li> <b>Percent</b> - produces a literal {@code '%'}
276 * (<tt>'\u0025'</tt>)
277 *
278 * <li> <b>Line Separator</b> - produces the platform-specific line separator
279 *
280 * </ol>
281 *
282 * <p> The following table summarizes the supported conversions. Conversions
283 * denoted by an upper-case character (i.e. {@code 'B'}, {@code 'H'},
284 * {@code 'S'}, {@code 'C'}, {@code 'X'}, {@code 'E'}, {@code 'G'},
285 * {@code 'A'}, and {@code 'T'}) are the same as those for the corresponding
286 * lower-case conversion characters except that the result is converted to
287 * upper case according to the rules of the prevailing {@link java.util.Locale
288 * Locale}. The result is equivalent to the following invocation of {@link
289 * String#toUpperCase()}
290 *
291 * <pre>
292 * out.toUpperCase() </pre>
293 *
1486 * BigDecimal#toString()}.
1487 *
1488 * </table>
1489 *
1490 * <p> All <a href="#intFlags">flags</a> defined for Byte, Short, Integer, and
1491 * Long apply.
1492 *
1493 * <p> If the {@code '#'} flag is given, then the decimal separator will
1494 * always be present.
1495 *
1496 * <p> The <a href="#floatdFlags">default behavior</a> when no flags are
1497 * given is the same as for Float and Double.
1498 *
1499 * <p> The specification of <a href="#floatDWidth">width</a> and <a
1500 * href="#floatDPrec">precision</a> is the same as defined for Float and
1501 * Double.
1502 *
1503 * <h4><a name="ddt">Date/Time</a></h4>
1504 *
1505 * <p> This conversion may be applied to {@code long}, {@link Long}, {@link
1506 * Calendar}, {@link Date} and {@link TemporalAccessor TemporalAccessor}
1507 *
1508 * <table cellpadding=5 summary="DTConv">
1509 *
1510 * <tr><td valign="top"> {@code 't'}
1511 * <td valign="top"> <tt>'\u0074'</tt>
1512 * <td> Prefix for date and time conversion characters.
1513 * <tr><td valign="top"> {@code 'T'}
1514 * <td valign="top"> <tt>'\u0054'</tt>
1515 * <td> The upper-case variant of {@code 't'}.
1516 *
1517 * </table>
1518 *
1519 * <p> The following date and time conversion character suffixes are defined
1520 * for the {@code 't'} and {@code 'T'} conversions. The types are similar to
1521 * but not completely identical to those defined by GNU {@code date} and
1522 * POSIX {@code strftime(3c)}. Additional conversion types are provided to
1523 * access Java-specific functionality (e.g. {@code 'L'} for milliseconds
1524 * within the second).
1525 *
1526 * <p> The following conversion characters are used for formatting times:
2780 print("null");
2781 return;
2782 }
2783 Calendar cal = null;
2784
2785 // Instead of Calendar.setLenient(true), perhaps we should
2786 // wrap the IllegalArgumentException that might be thrown?
2787 if (arg instanceof Long) {
2788 // Note that the following method uses an instance of the
2789 // default time zone (TimeZone.getDefaultRef().
2790 cal = Calendar.getInstance(l == null ? Locale.US : l);
2791 cal.setTimeInMillis((Long)arg);
2792 } else if (arg instanceof Date) {
2793 // Note that the following method uses an instance of the
2794 // default time zone (TimeZone.getDefaultRef().
2795 cal = Calendar.getInstance(l == null ? Locale.US : l);
2796 cal.setTime((Date)arg);
2797 } else if (arg instanceof Calendar) {
2798 cal = (Calendar) ((Calendar)arg).clone();
2799 cal.setLenient(true);
2800 } else if (arg instanceof TemporalAccessor) {
2801 print((TemporalAccessor)arg, c, l);
2802 return;
2803 } else {
2804 failConversion(c, arg);
2805 }
2806 // Use the provided locale so that invocations of
2807 // localizedMagnitude() use optimizations for null.
2808 print(cal, c, l);
2809 }
2810
2811 private void printCharacter(Object arg) throws IOException {
2812 if (arg == null) {
2813 print("null");
2814 return;
2815 }
2816 String s = null;
2817 if (arg instanceof Character) {
2818 s = ((Character)arg).toString();
2819 } else if (arg instanceof Byte) {
2820 byte i = ((Byte)arg).byteValue();
2821 if (Character.isValidCodePoint(i))
2822 s = new String(Character.toChars(i));
4033 case DateTime.DATE: { // 'D' (mm/dd/yy)
4034 char sep = '/';
4035 print(sb, t, DateTime.MONTH, l).append(sep);
4036 print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
4037 print(sb, t, DateTime.YEAR_2, l);
4038 break;
4039 }
4040 case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d)
4041 char sep = '-';
4042 print(sb, t, DateTime.YEAR_4, l).append(sep);
4043 print(sb, t, DateTime.MONTH, l).append(sep);
4044 print(sb, t, DateTime.DAY_OF_MONTH_0, l);
4045 break;
4046 }
4047 default:
4048 assert false;
4049 }
4050 return sb;
4051 }
4052
4053 private void print(TemporalAccessor t, char c, Locale l) throws IOException {
4054 StringBuilder sb = new StringBuilder();
4055 print(sb, t, c, l);
4056 // justify based on width
4057 String s = justify(sb.toString());
4058 if (f.contains(Flags.UPPERCASE))
4059 s = s.toUpperCase();
4060 a.append(s);
4061 }
4062
4063 private Appendable print(StringBuilder sb, TemporalAccessor t, char c,
4064 Locale l) throws IOException {
4065 if (sb == null)
4066 sb = new StringBuilder();
4067 try {
4068 switch (c) {
4069 case DateTime.HOUR_OF_DAY_0: { // 'H' (00 - 23)
4070 int i = t.get(ChronoField.HOUR_OF_DAY);
4071 sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l));
4072 break;
4073 }
4074 case DateTime.HOUR_OF_DAY: { // 'k' (0 - 23) -- like H
4075 int i = t.get(ChronoField.HOUR_OF_DAY);
4076 sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l));
4077 break;
4078 }
4079 case DateTime.HOUR_0: { // 'I' (01 - 12)
4080 int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM);
4081 sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l));
4082 break;
4083 }
4084 case DateTime.HOUR: { // 'l' (1 - 12) -- like I
4085 int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM);
4086 sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l));
4087 break;
4088 }
4089 case DateTime.MINUTE: { // 'M' (00 - 59)
4090 int i = t.get(ChronoField.MINUTE_OF_HOUR);
4091 Flags flags = Flags.ZERO_PAD;
4092 sb.append(localizedMagnitude(null, i, flags, 2, l));
4093 break;
4094 }
4095 case DateTime.NANOSECOND: { // 'N' (000000000 - 999999999)
4096 int i = t.get(ChronoField.MILLI_OF_SECOND) * 1000000;
4097 Flags flags = Flags.ZERO_PAD;
4098 sb.append(localizedMagnitude(null, i, flags, 9, l));
4099 break;
4100 }
4101 case DateTime.MILLISECOND: { // 'L' (000 - 999)
4102 int i = t.get(ChronoField.MILLI_OF_SECOND);
4103 Flags flags = Flags.ZERO_PAD;
4104 sb.append(localizedMagnitude(null, i, flags, 3, l));
4105 break;
4106 }
4107 case DateTime.MILLISECOND_SINCE_EPOCH: { // 'Q' (0 - 99...?)
4108 long i = t.getLong(ChronoField.INSTANT_SECONDS) * 1000L +
4109 t.getLong(ChronoField.MILLI_OF_SECOND);
4110 Flags flags = Flags.NONE;
4111 sb.append(localizedMagnitude(null, i, flags, width, l));
4112 break;
4113 }
4114 case DateTime.AM_PM: { // 'p' (am or pm)
4115 // Calendar.AM = 0, Calendar.PM = 1, LocaleElements defines upper
4116 String[] ampm = { "AM", "PM" };
4117 if (l != null && l != Locale.US) {
4118 DateFormatSymbols dfs = DateFormatSymbols.getInstance(l);
4119 ampm = dfs.getAmPmStrings();
4120 }
4121 String s = ampm[t.get(ChronoField.AMPM_OF_DAY)];
4122 sb.append(s.toLowerCase(l != null ? l : Locale.US));
4123 break;
4124 }
4125 case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?)
4126 long i = t.getLong(ChronoField.INSTANT_SECONDS);
4127 Flags flags = Flags.NONE;
4128 sb.append(localizedMagnitude(null, i, flags, width, l));
4129 break;
4130 }
4131 case DateTime.SECOND: { // 'S' (00 - 60 - leap second)
4132 int i = t.get(ChronoField.SECOND_OF_MINUTE);
4133 Flags flags = Flags.ZERO_PAD;
4134 sb.append(localizedMagnitude(null, i, flags, 2, l));
4135 break;
4136 }
4137 case DateTime.ZONE_NUMERIC: { // 'z' ({-|+}####) - ls minus?
4138 int i = t.get(ChronoField.OFFSET_SECONDS);
4139 boolean neg = i < 0;
4140 sb.append(neg ? '-' : '+');
4141 if (neg)
4142 i = -i;
4143 int min = i / 60;
4144 // combine minute and hour into a single integer
4145 int offset = (min / 60) * 100 + (min % 60);
4146 Flags flags = Flags.ZERO_PAD;
4147 sb.append(localizedMagnitude(null, offset, flags, 4, l));
4148 break;
4149 }
4150 case DateTime.ZONE: { // 'Z' (symbol)
4151 ZoneId zid = t.query(Queries.zone());
4152 if (zid == null) {
4153 throw new IllegalFormatConversionException(c, t.getClass());
4154 }
4155 if (!(zid instanceof ZoneOffset) &&
4156 t.isSupported(ChronoField.INSTANT_SECONDS)) {
4157 Instant instant = Instant.from(t);
4158 sb.append(TimeZone.getTimeZone(zid.getId())
4159 .getDisplayName(zid.getRules().isDaylightSavings(instant),
4160 TimeZone.SHORT,
4161 (l == null) ? Locale.US : l));
4162 break;
4163 }
4164 sb.append(zid.getId());
4165 break;
4166 }
4167 // Date
4168 case DateTime.NAME_OF_DAY_ABBREV: // 'a'
4169 case DateTime.NAME_OF_DAY: { // 'A'
4170 int i = t.get(ChronoField.DAY_OF_WEEK) % 7 + 1;
4171 Locale lt = ((l == null) ? Locale.US : l);
4172 DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
4173 if (c == DateTime.NAME_OF_DAY)
4174 sb.append(dfs.getWeekdays()[i]);
4175 else
4176 sb.append(dfs.getShortWeekdays()[i]);
4177 break;
4178 }
4179 case DateTime.NAME_OF_MONTH_ABBREV: // 'b'
4180 case DateTime.NAME_OF_MONTH_ABBREV_X: // 'h' -- same b
4181 case DateTime.NAME_OF_MONTH: { // 'B'
4182 int i = t.get(ChronoField.MONTH_OF_YEAR) - 1;
4183 Locale lt = ((l == null) ? Locale.US : l);
4184 DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
4185 if (c == DateTime.NAME_OF_MONTH)
4186 sb.append(dfs.getMonths()[i]);
4187 else
4188 sb.append(dfs.getShortMonths()[i]);
4189 break;
4190 }
4191 case DateTime.CENTURY: // 'C' (00 - 99)
4192 case DateTime.YEAR_2: // 'y' (00 - 99)
4193 case DateTime.YEAR_4: { // 'Y' (0000 - 9999)
4194 int i = t.get(ChronoField.YEAR);
4195 int size = 2;
4196 switch (c) {
4197 case DateTime.CENTURY:
4198 i /= 100;
4199 break;
4200 case DateTime.YEAR_2:
4201 i %= 100;
4202 break;
4203 case DateTime.YEAR_4:
4204 size = 4;
4205 break;
4206 }
4207 Flags flags = Flags.ZERO_PAD;
4208 sb.append(localizedMagnitude(null, i, flags, size, l));
4209 break;
4210 }
4211 case DateTime.DAY_OF_MONTH_0: // 'd' (01 - 31)
4212 case DateTime.DAY_OF_MONTH: { // 'e' (1 - 31) -- like d
4213 int i = t.get(ChronoField.DAY_OF_MONTH);
4214 Flags flags = (c == DateTime.DAY_OF_MONTH_0
4215 ? Flags.ZERO_PAD
4216 : Flags.NONE);
4217 sb.append(localizedMagnitude(null, i, flags, 2, l));
4218 break;
4219 }
4220 case DateTime.DAY_OF_YEAR: { // 'j' (001 - 366)
4221 int i = t.get(ChronoField.DAY_OF_YEAR);
4222 Flags flags = Flags.ZERO_PAD;
4223 sb.append(localizedMagnitude(null, i, flags, 3, l));
4224 break;
4225 }
4226 case DateTime.MONTH: { // 'm' (01 - 12)
4227 int i = t.get(ChronoField.MONTH_OF_YEAR);
4228 Flags flags = Flags.ZERO_PAD;
4229 sb.append(localizedMagnitude(null, i, flags, 2, l));
4230 break;
4231 }
4232
4233 // Composites
4234 case DateTime.TIME: // 'T' (24 hour hh:mm:ss - %tH:%tM:%tS)
4235 case DateTime.TIME_24_HOUR: { // 'R' (hh:mm same as %H:%M)
4236 char sep = ':';
4237 print(sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep);
4238 print(sb, t, DateTime.MINUTE, l);
4239 if (c == DateTime.TIME) {
4240 sb.append(sep);
4241 print(sb, t, DateTime.SECOND, l);
4242 }
4243 break;
4244 }
4245 case DateTime.TIME_12_HOUR: { // 'r' (hh:mm:ss [AP]M)
4246 char sep = ':';
4247 print(sb, t, DateTime.HOUR_0, l).append(sep);
4248 print(sb, t, DateTime.MINUTE, l).append(sep);
4249 print(sb, t, DateTime.SECOND, l).append(' ');
4250 // this may be in wrong place for some locales
4251 StringBuilder tsb = new StringBuilder();
4252 print(tsb, t, DateTime.AM_PM, l);
4253 sb.append(tsb.toString().toUpperCase(l != null ? l : Locale.US));
4254 break;
4255 }
4256 case DateTime.DATE_TIME: { // 'c' (Sat Nov 04 12:02:33 EST 1999)
4257 char sep = ' ';
4258 print(sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep);
4259 print(sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep);
4260 print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
4261 print(sb, t, DateTime.TIME, l).append(sep);
4262 print(sb, t, DateTime.ZONE, l).append(sep);
4263 print(sb, t, DateTime.YEAR_4, l);
4264 break;
4265 }
4266 case DateTime.DATE: { // 'D' (mm/dd/yy)
4267 char sep = '/';
4268 print(sb, t, DateTime.MONTH, l).append(sep);
4269 print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
4270 print(sb, t, DateTime.YEAR_2, l);
4271 break;
4272 }
4273 case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d)
4274 char sep = '-';
4275 print(sb, t, DateTime.YEAR_4, l).append(sep);
4276 print(sb, t, DateTime.MONTH, l).append(sep);
4277 print(sb, t, DateTime.DAY_OF_MONTH_0, l);
4278 break;
4279 }
4280 default:
4281 assert false;
4282 }
4283 } catch (DateTimeException x) {
4284 throw new IllegalFormatConversionException(c, t.getClass());
4285 }
4286 return sb;
4287 }
4288
4289 // -- Methods to support throwing exceptions --
4290
4291 private void failMismatch(Flags f, char c) {
4292 String fs = f.toString();
4293 throw new FormatFlagsConversionMismatchException(fs, c);
4294 }
4295
4296 private void failConversion(char c, Object arg) {
4297 throw new IllegalFormatConversionException(c, arg.getClass());
4298 }
4299
4300 private char getZero(Locale l) {
4301 if ((l != null) && !l.equals(locale())) {
4302 DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
4303 return dfs.getZeroDigit();
4304 }
4305 return zero;
4306 }
4307
4308 private StringBuilder
|