Number and date formats can also be used
separately, with similar control over their formatting. (Number formats handle general
numbers and currencies; date formats cover both dates and times.) To globalize your
program, replace the implicit conversion of a number to a string with an explicit
formatting call, and put the pattern for the format into a resource bundle. When doing so,
you should always get a number format using getInstance() in Java ( createInstance()
in C/C++), since a particular locale may have a specialized subclass of NumberFormat.
Number Output from String Resource
Java |
| Old |
| uniString = myNumber.toString(); |
| New |
| NumberFormat numFmt =
NumberFormat.getInstance(); uniString =
(numFmt.format(myNumber)).toString(); |
C++ |
| Old |
| sprintf(uniString,
"%d",myNumber); |
| New |
| NumberFormat *numFmt =
NumberFormat::createInstance(err); numFmt->format(myNumber,
uniString, 0); |
C |
| Old |
| sprintf)uniString,
"%d",myNumber); |
| New |
| NumberFormat *numFmt
= T_NumberFormat_createInstance(&err); T_NumberFormat_formatLong(numFmt,
myNumber, uniString); |
You can also programmatically alter number formats, such as by setting the maximum or
minimum number of decimals, or by deciding whether a thousands separator is used. However,
it is better practice to use a pattern string to allow your localization engineers to
customize the format.
Of course, if you are formatting in a tight loop, you should move the creation of the
format out of the loop! You can also make your formats static to avoid repeated creations
(when using Java or C++).
Instead of using methods on Integer (or sscanf for int and float
in C and C++) to do conversion from strings to numbers, dates, times, etc., use
the appropriate formats again for parsing. A Format will parse what it can
produce (and more), so you can use the same one for output and input.
Number Input
Java |
| Old |
| try { myNumber
= Integer.parseInt(myTextField.getText());
} catch (NumberFormatException e) {
alertBadNumber(e);
} |
| New |
| try { myNumber
= numFmt.parse(myTextField.getText());
} catch (ParseException e) {
alertBadNumber(e);
} |
C++ |
| Old |
| if (scanf("%d",
&myLong)<0) {/*error occurred*/... |
| New |
| numFmt->parse(myAsciiString,fmtLong,
err); myLong = fmtLong.getLong();
if (FAILURE(err)) {/*error occurred*/... |
C |
| Old |
| if (scanf("%d",
&myLong)<0) {/*error occurred*/... |
| New |
| T_NumberFormat_parse(numFmt,
myAsciiString, fmtLong, &err); myLong =
T_Formattable_getLong(fmtLong);
if (FAILURE(err)) {/*error occurred*/... |
if you are creating your own display of date fields, such as for an alarm clock widget,
then you may want to display the different component fields (year, month, date...) each in
a separate text field. Then you will want to use a Calendar, which will convert the
standard Date into its components according to local conventions.
Note
The order and choice of these fields may vary according to local conventions. For
example, the year may come at the start of the date instead of the end, or the date format
may even consist of very different information, such as year + day-in-year.
Currently, there is no simple way to get the order of the fields in the format; this is
expected to be addressed in a future release. In the meantime, if you intend to use FieldPosition
to determine the position of the fields within the text, be warned that there is a bug
that makes that difficult: consult the IBM Java Web
site for a workaround.
Calendar has special support for clock widgets. For any given field, it can
tell you the result of incrementing or decrementing that field. It also supports a variant
form of incrementing/decrementing, called rolling, which gives you the same effect
as setting a field on your digital watch, in which changing the minute field doesn't
affect the hour: ...11:58, 11:59, 11:00, 11:01...