|
When you are formatting date and time, you should be concerned with four locale-dependent issues:
The Java DateFormat class handles these issues. It is easy to use and quite similar to the NumberFormat class. First, you get a locale. You can use the default locale or call the static getAvailableLocales method to obtain an array of locales that support date formatting. Then, you call one of the three factory methods: fmt = DateFormat.getDateInstance(dateStyle, loc); fmt = DateFormat.getTimeInstance(timeStyle, loc); fmt = DateFormat.getDateTimeInstance(dateStyle, timeStyle, loc); To specify the desired style, these factory methods have a parameter that is one of the following constants:
The factory method returns a formatting object that you can then use to format dates. Date now = new Date(); String s = fmt.format(now); Just as with the NumberFormat class, you can use the parse method to parse a date that the user typed. For example, the following code parses the value that the user typed into a text field, using the default locale. TextField inputField; . . . DateFormat fmt = DateFormat.getDateInstance(DateFormat.MEDIUM); Date input = fmt.parse(inputField.getText().trim()); If the number was not typed correctly, this code throws a ParseException. Note that leading whitespace in the string is not allowed here, either. You should again call trim to remove it. However, any characters that follow the number in the string will again be ignored. Unfortunately, the user must type the date exactly in the expected format. For example, if the format is set to MEDIUM in the U.S. locale, then dates are expected to look like Sep 18, 1997 If the user types Sep 18 1997 (without the comma) or the short format 9/18/97 then a parse error results. A lenient flag interprets dates leniently. For example, February 30, 1999 will be automatically converted to March 2, 1999. This seems dangerous, but, unfortunately, it is the default. You should probably turn off this feature. The calendar object that interprets the parsed date will throw IllegalArgumentException when the user enters an invalid day/month/year combination. Example 10-2 shows the DateFormat class in action. You can select a locale and see how the date and time are formatted in different places around the world. If you see question-mark characters in the output, then you don't have the fonts installed for displaying characters in the local language. For example, if you pick a Chinese locale, the date may be expressed as 1997918 Figure 10-2 shows the program (after Chinese fonts were installed). As you can see, it correctly displays the output. Figure 10-2. The DateFormatTest programYou can also experiment with parsing. Enter a date or time, click the Parse lenient checkbox if desired, and click the Parse date or Parse time button. We use a helper class EnumCombo to solve a technical problem (see Example 10-3). We wanted to fill a combo with values such as Short, Medium, and Long and then automatically convert the user's selection to integer values DateFormat.SHORT, DateFormat.MEDIUM, and DateFormat.LONG. Rather than writing repetitive code, we use reflection: We convert the user's choice to upper case, replace all spaces with underscores, and then find the value of the static field with that name. (See Volume 1, Chapter 5 for more details about reflection.) TIP
Example 10-2. DateFormatTest.java1. import java.awt.*; 2. import java.awt.event.*; 3. import java.text.*; 4. import java.util.*; 5. import javax.swing.*; 6. 7. /** 8. This program demonstrates formatting dates under various locales. 9. */ 10. public class DateFormatTest 11. { 12. public static void main(String[] args) 13. { 14. JFrame frame = new DateFormatFrame(); 15. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 16. frame.setVisible(true); 17. } 18. } 19. 20. /** 21. This frame contains combo boxes to pick a locale, date and 22. time formats, text fields to display formatted date and time, 23. buttons to parse the text field contents, and a "lenient" 24. checkbox. 25. */ 26. class DateFormatFrame extends JFrame 27. { 28. public DateFormatFrame() 29. { 30. setTitle("DateFormatTest"); 31. 32. setLayout(new GridBagLayout()); 33. add(new JLabel("Locale"), new GBC(0, 0).setAnchor(GBC.EAST)); 34. add(new JLabel("Date style"), new GBC(0, 1).setAnchor(GBC.EAST)); 35. add(new JLabel("Time style"), new GBC(2, 1).setAnchor(GBC.EAST)); 36. add(new JLabel("Date"), new GBC(0, 2).setAnchor(GBC.EAST)); 37. add(new JLabel("Time"), new GBC(0, 3).setAnchor(GBC.EAST)); 38. add(localeCombo, new GBC(1, 0, 2, 1).setAnchor(GBC.WEST)); 39. add(dateStyleCombo, new GBC(1, 1).setAnchor(GBC.WEST)); 40. add(timeStyleCombo, new GBC(3, 1).setAnchor(GBC.WEST)); 41. add(dateParseButton, new GBC(3, 2).setAnchor(GBC.WEST)); 42. add(timeParseButton, new GBC(3, 3).setAnchor(GBC.WEST)); 43. add(lenientCheckbox, new GBC(0, 4, 2, 1).setAnchor(GBC.WEST)); 44. add(dateText, new GBC(1, 2, 2, 1).setFill(GBC.HORIZONTAL)); 45. add(timeText, new GBC(1, 3, 2, 1).setFill(GBC.HORIZONTAL)); 46. 47. locales = DateFormat.getAvailableLocales(); 48. for (Locale loc : locales) localeCombo.addItem(loc.getDisplayName()); 49. localeCombo.setSelectedItem(Locale.getDefault().getDisplayName()); 50. currentDate = new Date(); 51. currentTime = new Date(); 52. updateDisplay(); 53. 54. ActionListener listener = new 55. ActionListener() 56. { 57. public void actionPerformed(ActionEvent event) 58. { 59. updateDisplay(); 60. } 61. }; 62. 63. localeCombo.addActionListener(listener); 64. dateStyleCombo.addActionListener(listener); 65. timeStyleCombo.addActionListener(listener); 66. 67. dateParseButton.addActionListener(new 68. ActionListener() 69. { 70. public void actionPerformed(ActionEvent event) 71. { 72. String d = dateText.getText().trim(); 73. try 74. { 75. currentDateFormat.setLenient(lenientCheckbox.isSelected()); 76. Date date = currentDateFormat.parse(d); 77. currentDate = date; 78. updateDisplay(); 79. } 80. catch (ParseException e) 81. { 82. dateText.setText("Parse error: " + d); 83. } 84. catch (IllegalArgumentException e) 85. { 86. dateText.setText("Argument error: " + d); 87. } 88. } 89. }); 90. 91. timeParseButton.addActionListener(new 92. ActionListener() 93. { 94. public void actionPerformed(ActionEvent event) 95. { 96. String t = timeText.getText().trim(); 97. try 98. { 99. currentDateFormat.setLenient(lenientCheckbox.isSelected()); 100. Date date = currentTimeFormat.parse(t); 101. currentTime = date; 102. updateDisplay(); 103. } 104. catch (ParseException e) 105. { 106. timeText.setText("Parse error: " + t); 107. } 108. catch (IllegalArgumentException e) 109. { 110. timeText.setText("Argument error: " + t); 111. } 112. } 113. }); 114. pack(); 115. } 116. 117. /** 118. Updates the display and formats the date according 119. to the user settings. 120. */ 121. public void updateDisplay() 122. { 123. Locale currentLocale = locales[localeCombo.getSelectedIndex()]; 124. int dateStyle = dateStyleCombo.getValue(); 125. currentDateFormat = DateFormat.getDateInstance(dateStyle, currentLocale); 126. String d = currentDateFormat.format(currentDate); 127. dateText.setText(d); 128. int timeStyle = timeStyleCombo.getValue(); 129. currentTimeFormat = DateFormat.getTimeInstance(timeStyle, currentLocale); 130. String t = currentTimeFormat.format(currentTime); 131. timeText.setText(t); 132. } 133. 134. private Locale[] locales; 135. private Date currentDate; 136. private Date currentTime; 137. private DateFormat currentDateFormat; 138. private DateFormat currentTimeFormat; 139. private JComboBox localeCombo = new JComboBox(); 140. private EnumCombo dateStyleCombo = new EnumCombo(DateFormat.class, 141. new String[] { "Default", "Full", "Long", "Medium", "Short" }); 142. private EnumCombo timeStyleCombo = new EnumCombo(DateFormat.class, 143. new String[] { "Default", "Full", "Long", "Medium", "Short" }); 144. private JButton dateParseButton = new JButton("Parse date"); 145. private JButton timeParseButton = new JButton("Parse time"); 146. private JTextField dateText = new JTextField(30); 147. private JTextField timeText = new JTextField(30); 148. private JTextField parseText = new JTextField(30); 149. private JCheckBox lenientCheckbox = new JCheckBox("Parse lenient", true); 150. } Example 10-3. EnumCombo.java1. import java.util.*; 2. import javax.swing.*; 3. 4. /** 5. A combo box that lets users choose from among static field 6. values whose names are given in the constructor. 7. */ 8. public class EnumCombo extends JComboBox 9. { 10. /** 11. Constructs an EnumCombo. 12. @param cl a class 13. @param labels an array of static field names of cl 14. */ 15. public EnumCombo(Class cl, String[] labels) 16. { 17. for (int i = 0; i < labels.length; i++) 18. { 19. String label = labels[i]; 20. String name = label.toUpperCase().replace(' ', '_'); 21. int value = 0; 22. try 23. { 24. java.lang.reflect.Field f = cl.getField(name); 25. value = f.getInt(cl); 26. } 27. catch (Exception e) 28. { 29. label = "(" + label + ")"; 30. } 31. table.put(label, value); 32. addItem(label); 33. } 34. setSelectedItem(labels[0]); 35. } 36. 37. /** 38. Returns the value of the field that the user selected. 39. @return the static field value 40. */ 41. public int getValue() 42. { 43. return table.get(getSelectedItem()); 44. } 45. 46. private Map<String, Integer> table = new TreeMap<String, Integer>(); 47. } java.text.DateFormat 1.1
java.util.TimeZone 1.1
|
|