Τετάρτη 12 Σεπτεμβρίου 2007

java.util.Formatter

Since JDK 1.5, java has java.util.Formatter class, an interpreter for printf-style format strings. However, the API for java.util.Formatter is rather obscure to understand. This blog is to help you see each format command and its result and be able to use the most appropriate format string for your case right away, without the need to go through the long Java API for this class.

The following info applies to:
  • Formatter.format()
  • String.format()
  • java.io.PrintStream.format()
  • java.io.PrintWriter.format()
  • printf()
but String.format() is only shown here for convenience. The same arguments can be used for the other 2 methods.

Here is a test case to display the use of format strings for date/time. I use this date as an example: 07-01-2007 22:05:01 (7th of January 2007, my name day!)

import java.text.SimpleDateFormat;
import java.util.Calendar;

import junit.framework.TestCase;

/**
* Class to test java.util.Formatter
* @author jkost
* @see java.util.Formatter
* @since JDK 1.5
*/
public class FormatterTester extends TestCase {
private final SimpleDateFormat sf = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");
private Calendar cal = Calendar.getInstance();

protected void setUp() throws Exception {
super.setUp();
cal.setTime(sf.parse("07-01-2007 22:05:01"));
}
/**
* Conversion characters for formatting dates.
*
*/
public void testDateFormatter() {
// full day of week
assertEquals("Sunday", String.format("%tA", cal));
// abbreviated day of week
assertEquals("Sun", String.format("%ta", cal));
// full month name
assertEquals("January", String.format("%tB", cal));
// abbreviated month name
assertEquals("Jan", String.format("%tb", cal));
assertEquals("Jan", String.format("%th", cal));
// the century, 00 to 99, i.e. year divided by 100
assertEquals("20", String.format("%tC", cal));
// day of month, 2-digit format
assertEquals("07", String.format("%td", cal));
// day of month, 1-digit format, i.e. without leading zeros
assertEquals("7", String.format("%te", cal));
// Date formatted as "m/d/y" (short numeric form)
assertEquals("01/07/07", String.format("%tD", cal));
// ISO 8601 complete date formatted as "Y-m-d".
assertEquals("2007-01-07", String.format("%tF", cal));
// 3-digit day of year
assertEquals("007", String.format("%tj", cal));
// 2-digit, month of year
assertEquals("01", String.format("%tm", cal));
// no week of year; SUN needs to implement this
// assertEquals("01", String.format("%tw", cal));
// 4-digit year
assertEquals("2007", String.format("%tY", cal));
// last 2 digits of year
assertEquals("07", String.format("%ty", cal));
}

/**
* Conversion characters for formatting times.
*
*/
public void testTimeFormatter() {
// 24-hour of day, 2-digit format, 00-23
assertEquals("22", String.format("%tH", cal));
// 12-hour of day, 2-digit format, 00-12
assertEquals("10", String.format("%tI", cal));
// 24-hour of day, 1-digit format, 0-23
assertEquals("22", String.format("%tk", cal));
// 12-hour of day, 1-digit format, 0-12
assertEquals("10", String.format("%tl", cal));
// minutes, 2-digit format, 00-59
assertEquals("05", String.format("%tM", cal));
// seconds, 2-digit format, 00-59
assertEquals("01", String.format("%tS", cal));
// milliseconds, 3-digit format, 000-999
assertEquals("000", String.format("%tL", cal));
// nanoseconds, 9-digit format, 000000000 - 999999999
assertEquals("000000000", String.format("%tN", cal));
// am or pm
assertEquals("pm", String.format("%tp", cal));
// AM or PM
assertEquals("PM", String.format("%Tp", cal));
// RFC 822 style numeric time zone offset from GMT, e.g. -0800.
assertEquals("+0100", String.format("%tz", cal));
// the abbreviation for the time zone
assertEquals("CET", String.format("%tZ", cal));
// Seconds since the beginning of the epoch starting at 1 January 1970 00:00:00 UTC,
// i.e. Long.MIN_VALUE/1000 to Long.MAX_VALUE/1000.
assertEquals("1168203901", String.format("%ts", cal));
// Milliseconds since the beginning of the epoch starting at 1 January 1970 00:00:00 UTC,
// i.e. Long.MIN_VALUE to Long.MAX_VALUE.
assertEquals("1168203901000", String.format("%tQ", cal));
// Time formatted for the 24-hour clock as "%tH:%tM"
assertEquals("22:05", String.format("%tR", cal));
// Time formatted for the 24-hour clock as "HH:MM:SS".
assertEquals("22:05:01", String.format("%tT", cal));
// Time formatted for the 12-hour clock as "hh:mm:ss AM/PM"
assertEquals("10:05:01 PM", String.format("%tr", cal));
}

/**
* Conversion characters for formatting date/time compositions.
*
*/
public void testDateTimeFormatter() {
// Date and time formatted as e.g. "Sun Jul 20 16:17:00 EDT 1969".
assertEquals("Sun Jan 07 22:05:01 CET 2007", String.format("%tc", cal));
}

/**
* Formats the value as either "true" or "false" (or "TRUE" or "FALSE", for %B).
* For boolean values, this works as expected.
* For all other values, any non-null value is "true", while null values are "false".
* %type
* type = b | B | s | S
*
*/
public void testBooleanFormatter() {
final boolean flag = true;
// boolean
assertEquals("true", String.format("%b", flag));
// boolean
assertEquals("TRUE", String.format("%B", flag));

// as string
assertEquals("true", String.format("%s", flag));
assertEquals("TRUE", String.format("%S", flag));

assertEquals("false", String.format("%b", null));
assertEquals("true", String.format("%b", 1));
assertEquals("true", String.format("%b", 'a'));
}

/**
* Formats the value supplied as a single character.
* Supplied value must be a Byte, Short, Character, or Integer.
* %[argument][width]type
* argument = <
* width = any positive integer value
* type = c | C | s | S
*
*/
public void testCharacterFormatter() {
final char c = 'a';
// character
assertEquals("a", String.format("%c", c));
// character
assertEquals("A", String.format("%C", c));
// as string
assertEquals("a", String.format("%s", c));
assertEquals("A", String.format("%S", c));
}

/**
* %[argument][flags][width]type
* argument = <
* flags = - | + | # | | ( | 0
* width = any positive integer value
* type = d | o | x | X | H | s
* Arguments must be Byte, Short, Integer, Long, or BigInteger.
*/
public void testIntegerFormatter() {
final int intNumber = 7;

// base-10 integer
assertEquals("7", String.format("%d", intNumber));

// base-8 (octal) integer
assertEquals("16", String.format("%o", 2*intNumber)); // 2*7 = 14

// flag '#' indicates that formatted output should appear in alternate form.
// For %o, this means a leading 0.
assertEquals("07", String.format("%#o", intNumber));

// base-16 (hexadecimal) integer
assertEquals("e", String.format("%x", 2*intNumber)); // 2*7 = 14
assertEquals("E", String.format("%X", 2*intNumber)); // 2*7 = 14

// flag '#' indicates that formatted output should appear in alternate form.
// For %x and %X, output will include a leading 0x (0X).
assertEquals("0x7", String.format("%#x", intNumber));
assertEquals("0X7", String.format("%#X", intNumber));

// hexadecimal representation of the value's hashcode
assertEquals("e", String.format("%h", 2*intNumber)); // 2*7 = 14
assertEquals("E", String.format("%H", 2*intNumber)); // 2*7 = 14

// as string
assertEquals("7", String.format("%s", intNumber));

// width 3
assertEquals(" 7", String.format("%3d", intNumber));

// flag '-' means left justification
assertEquals("7 ", String.format("%-3d", intNumber));

// flag '+' indicates that numeric output should always include a sign (+ or -).
assertEquals("+7", String.format("%+d", intNumber));

// flag '(' indicates that negative numbers should appear in parentheses.
assertEquals("(7)", String.format("%(d", -intNumber));

// flag '0' indicates that numeric values should be padded on the left.
assertEquals("007", String.format("%03d", intNumber));

// flag ' ' (space) indicates that non-negative values should be prefixed with a space
// (for alignment with negative numbers).
assertEquals(" 7", String.format("% d", intNumber));

// flag '#' indicates that formatted output should appear in alternate form.
// For %s and %S, the flag is passed on to the object's formatTo( ) method.
// The # flag only works in conjunction with %s and %S if the argument
// implements java.util.Formattable.
assertEquals("7", String.format("%#s", intNumber));

// argument < indicates that the previous argument should be used (again),
// rather than continuing on
assertEquals("+7 7", String.format("%+d %
<3d", , intNumber));
}

/**
* %[argument][flags][width][.precision]type
* argument =
<
* flags = - | + | # | | ( | 0 | ,
* width = any positive integer value
* precision = any positive integer value
* type = f | a | g | G | e | E | h | H | s
* Arguments must be Float, Double, or BigDecimal.
*/
public void testDoubleFormatter() {
final double doubleNumber = 7.0d;

// double/float number, 6 decimal digits by default
assertEquals("7.000000", String.format("%f", doubleNumber));

// double/float number, 5 max decimal digits
// precision is the total number of significant digits to be displayed
assertEquals("7.00000", String.format("%g", doubleNumber));
assertEquals("7.00000", String.format("%G", doubleNumber));

// exponential notation, default number of decimal digits 6
assertEquals("7.000000e+00", String.format("%e", doubleNumber));
assertEquals("7.000000E+00", String.format("%E", doubleNumber));

// exponential notation, using base-16 for the decimal part,
// and base-10 for the exponent part
assertEquals("0x1.cp2", String.format("%a", doubleNumber));

// hexadecimal representation of the value's hashcode
// precision determines the maximum characters output
assertEquals("401c0000", String.format("%h", doubleNumber));
assertEquals("401C0000", String.format("%H", doubleNumber));

// as string
// precision determines the maximum characters output
assertEquals("7.0", String.format("%s", doubleNumber));

// 2 decimal digits (precision = 2)
assertEquals("7.00", String.format("%.2f", doubleNumber));

// width 6, precision = 2 (2 decimal digits)
assertEquals(" 7.00", String.format("%6.2f", doubleNumber));

// flag '-' means left justification
assertEquals("7.00 ", String.format("%-6.2f", doubleNumber));

// flag '+' indicates that numeric output should always include a sign (+ or -).
assertEquals(" +7.00", String.format("%+6.2f", doubleNumber));

// flag '(' indicates that negative numbers should appear in parentheses.
assertEquals("(7.00)", String.format("%(.2f", -doubleNumber));

// flag '0' indicates that numeric values should be padded on the left.
assertEquals("007.00", String.format("%06.2f", doubleNumber));

// flag ',' indicates that the locale-specific grouping character
// should be used for numeric values.
assertEquals("7,00", String.format(new Locale("el"), "%,.2f", doubleNumber));

// flag ' ' (space) indicates that non-negative values should be prefixed with a space
// (for alignment with negative numbers).
assertEquals(" 7.00", String.format("% .2f", doubleNumber));


// argument < indicates that the previous argument should be used (again),
// rather than continuing on
assertEquals("7.00 7.0", String.format("%.2f %
<3.1f", doubleNumber));
}

public void
testIntegerNumberFormatter() {
final double
intNumber = 7;

// another way to format integers
NumberFormat nf = NumberFormat.getInstance();
nf.setMinimumIntegerDigits(3);
nf.setParseIntegerOnly(true);
assertEquals("007", nf.format(intNumber));
}
}

Δεν υπάρχουν σχόλια: