Certification Objective Dates, Numbers, and Currency (Exam Objective 3.4)


Certification Objective —Dates, Numbers, and Currency (Exam Objective 3.4)

3.4 Use standard J2SE APIs in the java.text package to correctly format or parse dates, numbers and currency values for a specific locale; and, given a scenario, determine the appropriate methods to use if you want to use the default locale or a specific locale. Describe the purpose and use of the java.util.Locale class.

The Java API provides an extensive (perhaps a little too extensive) set of classes to help you work with dates, numbers, and currency. The exam will test your knowledge of the basic classes and methods you'll use to work with dates and such. When you've finished this section you should have a solid foundation in tasks such as creating new Date and DateFormat objects, converting Strings to Dates and back again, performing Calendaring functions, printing properly formatted currency values, and doing all of this for locations around the globe. In fact, a large part of why this section was added to the exam was to test whether you can do some basic internationalization (often shortened to "i18n").

Working with Dates, Numbers, and Currencies

If you want to work with dates from around the world (and who doesn't?), you'll need to be familiar with at least four classes from the java.text and java.util packages. In fact, we'll admit it right up front, you might encounter questions on the exam that use classes that aren't specifically mentioned in the Sun objective. Here are the four date related classes you'll need to understand:

  • java.util.Date Most of this class's methods have been deprecated, but you can use this class to bridge between the Calendar and DateFormat class. An instance of Date represents a mutable date and time, to a millisecond.

  • java.util.Calendar This class provides a huge variety of methods that help you convert and manipulate dates and times. For instance, if you want to add a month to a given date, or find out what day of the week January 1, 3000 falls on, the methods in the Calendar class will save your bacon.

  • java.text.DateFormat This class is used to format dates not only providing various styles such as "01/01/70" or "January 1, 1970," but also to format dates for numerous locales around the world.

  • Java.text.NumberFormat This class is used to format numbers and currencies for locales around the world.

  • Java.util.Locale This class is used in conjunction with DateFormat and NumberFormat to format dates, numbers and currency for specific locales. With the help of the Locale class you'll be able to convert a date like "10/08/2005" to "Segunda-feira, 8 de Outubro de 2005" in no time. If you want to manipulate dates without producing formatted output, you can use the Locale class directly with the Calendar class.

Orchestrating Date- and Number-Related Classes

When you work with dates and numbers, you'll often use several classes together. It's important to understand how the classes we described above relate to each other, and when to use which classes in combination. For instance, you'll need to know that if you want to do date formatting for a specific locale, you need to create your Locale object before your DateFormat object, because you'll need your Locale object as an argument to your DateFormat factory method. Table 6-2 provides a quick overview of common date- and number-related use cases and solutions using these classes. Table 6-2 will undoubtedly bring up specific questions about individual classes, and we will dive into specifics for each class next. Once you've gone through the class level discussions, you should find that Table 6-2 provides a good summary.

Table 6-2: Common Use Cases When Working with Dates and Numbers

Use Case

Steps 1

Get the currect date and time

  1. Create a Date: Date d = new Date();

  2. Get its value: String s = d.toString();

Get an object that lets You perform date and time calculations in your locale.

  1. Create a Calender:

     Calender c = Calender.getInstance(); 

  2. Use c.add(...) and c.roll(...) to perform date and time manipulations.

Get an object that lets you perform date and time calculations in a different locale.

  1. Create a Locale:

    Locale loc = new Locale (language); or

    Locale loc = new Locale (language, country);

  2. Create a Calendar for that locale:

     Calendar c = Calendar.getInstance(loc) 

  3. Use c.add(...) and c.roll(...) to perform date and time manipulations.

Get an object that lets you perform date and time calculations, and then format it for output in different locales with different date styles.

  1. Create a Calendar:

     Calendar c = Calendar.getInstance(); 

  2. Create a Locale for each location:

     Locale loc = new Locale(...); 

  3. Convert your Calendar to a Date:

     Date d = c.getTime(); 

  4. Create a DateFormat for each Locale:

     DateFormat df = DateFormat.getDateInstance (style, loc); 

  5. Use the format() method to create formatted dates:

     String s = df.format(d); 

Get an object that lets you format numbers or currencies across many different locales.

  1. Create a Locale for each location:

     Locale loc = new Locale(...); 

  2. Create a NumberFormat:

    NumberFormat nf = NumberFormat.getInstance(loc); -or- NumberFormat nf = NumberFormat.getCurrencyInstance(loc);

    3.Use the format() method to create formatted output:

     String s = nf.format(someNumber); 

The Date Class

The Date class has a checkered past. Its API design didn't do a good job of handling internationalization and localization situations. In its current state, most of its ethods have been deprecated, and for most purposes you'll want to use the Calendar class instead of the Date class. The Date class is on the exam for several reasons: you might find it used in legacy code, it's really easy if all you want is a quick and dirty way to get the current date and tune, it's good when you want a universal time that is not affected by time zones, and finally, you'll use it as a temporary bridge to format a Calendar object using the DateForrnat class.

As we mentioned briefly above, an instance of the Date class represents a single date and time. Internally, the date and time is stored as a primitive long. Specifically, the long holds the number of milliseconds (you know, 1000 of these per second), between the date being represented and January 1, 1970.

Have you ever tried to grasp how big really big numbers are? Let's use the Date class to find out how long it took for a trillion milliseconds to pass, starting at January 1, 1970:

 import java.util.*; class TestDates {   public static void main(String[] args) {     Date d1 = new Date(1000000000000L);  // a trillion!     System.out.println("1st date " + d1.tostring());   } } 

On our JVM, which has a US locale, the output is

 1st date Sat Sep OB 19:46:40 MDT 2001 

Okay, for future reference remember that there are a trillion milliseconds for every 31 and 2/3 years.

Although most of Date's methods have been deprecated, it's still acceptable to use the getTime and setTime methods, although as we'll soon see, it's a bit painful. Let's add an hour to our Date instance, d1, from the previous example:

 import java.util.*; class TestDates   public static void main(String[] args) {     Date d1 = new Date(1000000000000L);  // a trillion!     System.out.println("1st date " + d1.toString());     d1.setTime(d1.getTime() + 3600000); // 3600000 millis / hour     System.out.println("new time " + d1.toString());   } } 

which produces (again, on our JVM):

 1st date Sat Sep 08 19:46:40 MDT 2001 new time Sat Sep 08 20:46:40 MDT 2001 

Notice that both setTime() and getTime() used the handy millisecond scaleif you want to manipulate dates using the Date class, that's your only choice. While that wasn't too painful, imagine how much fun it would be to add, say, a year to a given date.

We'll revisit the Date class later on, but for now the only other thing you need to know is that if you want to create an instance of Date to represent "now," you use Date's no-argument constructor:

 Date now = new Date(); 

(We're guessing that if you call now.getTime(), you'll get a number somewhere between one trillion and two trillion.)

The Calendar Class

We've just seen that manipulating dates using the Date class is tricky. The Calendar class is designed to make date manipulation easy! (Well, easier.) While the Calendar class has about a million fields and methods, once you get the hang of a few of them the rest tend to work in a similar fashion.

When you first try to use the Calendar class you might notice that it's an abstract class. You can't say

 Calendar c = new Calendar();   // illegal, Calendar is abstract 

In order to create a Calendar instance, you have to use one of the overloaded getInstance() static factory methods:

 Calendar cal = Calendar.getInstance(); 

When you get a Calendar reference like cal, from above, your Calendar reference variable is actually referring to an instance of a concrete subclass of Calendar. You can't know for sure what subclass you'll get (java.util.GregorianCalendar is what you'll almost certainly get), but it won't matter to you. You'll be using Calendar's API. (As Java continues to spread around the world, in order to maintain cohesion, you might find additional, locale-specific subclasses of calendar.)

Okay, so now we've got an instance of Calendar, let's go back to our earlier example, and find out what day of the week our trillionth millisecond falls on, and then let's add a month to that date:

 import java.util.*; class Dates2 {   public static void main(String[] args) {     Date d1 = new Date(1000000000000L);     System.out.println("1st date " + d1.toString());     Calendar c = Calendar. getInstance();     c.setTime(dl);                          // #1     if(c.SUNDAY == c. getFirstDayofWeek()   // #2       System.out.println("Sunday is the first day of the week");     System.out.println("trillionth milli day of week is "                        + c.get(c.DAY_OF_WEEK));    // #3     c. add(Calendar. MONTH, 1);                    // #4     Date d2 = c.getTime();                         // #5     System.out.println("new date " + d2.toString() );   } } 

This produces something like

 1st date Sat Sep 08 19:46:40 MDT 2001 Sunday is the first day of the week trillionth milli day of week is 7 new date Mon Oct 08 20:46:40 MDT 2001 

Let's take a look at this program, focusing on the five highlighted lines:

  1. We assign the Date d1 to the Calendar instance c.

  2. We use Calendar's SUNDAY field to determine whether, for our JVM, SUNDAY is considered to be the first day of the week. (In some locales, MONDAY is the first day of the week.) The Calendar class provides similar fields for days of the week, months, the day of the month, the day of the year, and so on.

  3. We use the DAY_OF_WEEK field to find out the day of the week that the trillionth millisecond falls on.

  4. So far we've used setter and getter methods that should be intuitive to figure out. Now we're going to use Calendar's add() method. This very powerful method let's you add or subtract units of time appropriate for whichever Calendar field you specify. For instance:

     c.add(Calendar.HOUR, -4);    // subtract 4 hours from c's value c.add(Calendar.YEAR, 2);          // add 2 years to c's value c.add(Calendar.DAY_OF_WEEK, -2);  // subtract two days from                                   // c's  value 

  5. Convert c's value back to an instance of Date.

The other Calendar method you should know for the exam is the roll() method. The roll() method acts like the add() method, except that when a part of a Date gets incremented or decremented, larger parts of the Date will not get incremented or decremented. Hmmmfor instance:

 // assume c is October 8, 2001 c.roll(Calendar.MONTH, 9);      // notice the year in the output Date d4 = c.getTime(); System.out.println("new date " + d4.toString() ); 

The output would be something like this

 new date Fri Jul 08 19:46:40 MDT 2001 

Notice that the year did not change, even though we added 9 months to an October date. In a similar fashion, invoking roll() with HOUR won't change the date, the month or the year.

For the exam, you won't have to memorize the Calendar class's fields. If you need them to help answer a question, they will be provided as part of the question.

The DateFormat Class

Having learned how to create dates and manipulate them, let's find out how to format them. So that we're all on the same page, here's an example of how a date can be formatted in different ways:

 import java.text.*; import java.util.*; class Dates3 {   public static void main(String[] args) {     Date d1 = new Date(1000000000000L);     DateFormat[] dfa = new DateFormat[6];     dfa[0] = DateFormat.getInstance();     dfa[1] = DateFormat.getDateInstance();     dfa[2] = DateFormat.getDateInstance(DateFormat.SHORT);     dfa[3] = DateFormat.getDateInstance(DateFormat.MEDIUM);     dfa[4] = DateFormat.getDateInstance(DateFormat.LONG);     dfa[5] = DateFormat.getDateInstance(DateFormat.FULL);     for(DateFormat df : dfa)       System.out.println(df.format(d1));   } } 

which on our JVM produces

 9/8/01 7:46 PM Sep 8, 2001 9/8/01 Sep 8, 2001 September 8, 2001 Saturday, September 8, 2001 

Examining this code we see a couple of things right away. First off, it looks like DateFormat is another abstract class, so we can't use new to create instances of DateFormat. In this case we used two factory methods, getInstance() and getDateInstance(). Notice that getDateInstance() is overloaded; when we discuss locales, we'll look at the other version of getDateInstance() that you'll need to understand for the exam.

Next, we used static fields from the DateFormat class to customize our various instances of DateFormat. Each of these static fields represents a formatting style. In this case it looks like the no-arg version of getDateInstance() gives us the same style as the MEDIUM version of the method, but that's not a hard and fast rule. (More on this when we discuss locales.) Finally, we used the format() method to create Strings representing the properly formatted versions of the Date we're working with.

The last method you should be familiar with is the parse() method. The parse() method takes a String formatted in the style of the DateFormat instance being used, and converts the String into a Date object. As you might imagine, this is a risky operation because the parse() method could easily receive a badly formatted String. Because of this, parse() can throw a ParseException. The following code creates a Date instance, uses DateFormat.format() to convert it into a String, and then uses DateFormat.parse() to change it back into a Date:

 Date d1 = new Date(1000000000000L); System.out.println("d1 = " + d1.tostring()); DateFormat df = DateFormat.getDateInstance(                                  DateFormat.SHORT); String s = df.format(d1); System.out.println(s); try {   Date d2 = df.parse(s);   System.out.println("parsed = " + d2.toString()); } catch (ParseException pe) {   System.out.println("parse exc"); } 

which on our JVM produces

 d1 = Sat Sep 08 19:46:40 MDT 2001 9/8/01 parsed = Sat Sep 08 00:00:00 MDT 2001 

Notice that because we were using a SHORT style, we lost some precision when we converted the Date to a String. This loss of precision showed up when we converted back to a Date object, and it went from being 7:46 to midnight.

On the Job 

The API for DateFormat.parse() explains that by default, the parse() method is lenient when parsing dates. Our experience is that parse() isn't very lenient about the formatting of Strings it will successfully parse into dates; take care when you use this method!

The Locale Class

Earlier we said that a big part of why this objective exists is to test your ability to do some basic internationalization tasks. Your wait is over; the Locale class is your ticket to worldwide domination. Both the DateFormat class and the NumberFormat class (which we'll cover next) can use an instance of Locale to customize formatted output to be specific to a locale. You might ask how Java defines a locale? The API says a locale is "a specific geographical, political, or cultural region." The two Locale constructors you'll need to understand for the exam are

 Locale(String language) Locale(String language, String country) 

The language argument represents an ISO 639 Language Code, so for instance if you want to format your dates or numbers in Walloon (the language sometimes used in southern Belgium), you'd use "wa" as your language string. There are over 500 ISO Language codes, including one for Klingon ("tlh"), although unfortunately Java doesn't yet support the Klingon locale. We thought about telling you that you'd have to memorize all these codes for the exambut we didn't want to cause any heart attacks. So rest assured, you won't have to memorize any ISO Language codes or ISO Country codes (of which there are about 240) for the exam.

Let's get back to how you might use these codes. If you want to represent basic Italian in your application, all you need is the language code. If, on the other hand, you want to represent the Italian used in Switzerland, you'd want to indicate that the country is Switzerland (yes, the country code for Switzerland is "CH"), but that the language is Italian:

 Locale locPT = new Locale("it");        // Italian Locale locBR = new Locale("it", "CH");  // Switzerland 

Using these two locales on a date could give us output like this:

 sabato 1 ottobre 2005 sabato, 1. ottobre 2005 

Now let's put this all together in some code that creates a Calendar object, sets its date, then converts it to a Date. After that we'll take that Date object and print it out using locales from around the world:

 Calendar c = Calendar.getlnstance(); c.set(2010, 11, 14);                  // December 14, 2010                                       // (month is 0-based Date d2 = c.getTime(); Locale locIT = new Locale("it", "IT");  // Italy Locale locPT = new Locale("pt");        // Portugal Locale locBR = new Locale("pt", "BR");  // Brazil Locale locIN = new Locale("hi", "IN");  // India Locale locJA = new Locale("ja");        // Japan DateFormat dfUS = DateFormat.getInstance(); System.out.println("US       " + dfUS.format(d2)); DateFormat dfUSfull = DateFormat.getDateInstance(                                         DateFormat.FULL); System.out.println("US full " + dfUSfull.format(d2)); DateFormat dfIT = DateFormat.getDatelnstance(                                         DateFormat.FULL, locIT); System.out.println("Italy    " + dfIT.format(d2)); DateFormat dfPT = DateFormat.getDateInstance(                                         DateFormat.FULL, locPT); System.out.println("Portugal " + dfPT.format(d2)); DateFormat dfBR = DateFormat.getDateInstance(                                         DateFormat.FULL, locBR); System.out.println("Brazil " + dfBR.format(d2)); DateFormat dfIN = DateFormat.getDateInstance(                                         DateFormat.FULL, locIN); System.out.println("India    " + dfIN.format(d2)); DateFormat dfJA = DateFormat.getDateInstance(                                         DateFormat.FULL, locJA); System.out.println("Japan    " + dfJA.format(d2)); 

This, on our JVM, produces

 US        12/14/10 3:32 PM US full   Sunday, December 14, 2010 Italy     domenica 14 dicembre 2010 Portugal Domingo, 14 de Dezembro de 2010 Brazil.  Domingo, 14 de Dezembro de 2010 India    ??????, ?? ??????, ???? Japan    2010?12?14? 

Oops! Our machine isn't configured to support locales for India or Japan, but you can see how a single Date object can be formatted to work for many locales.

image from book
Exam Watch

Remember that both DateFormat and NumberFormat objects can have their locales set only at the time of instantiation. Watch for code that attempts to change the locale of an existing instance—no such methods exist!

image from book

There are a couple more methods in Locale (getDisplayCountry() and getDisplayLanguage()) that you'll have to know for the exam. These methods let you create Strings that represent a given locale's country and language in terms of both the default locale and any other locale:

 Calendar c = Calendar.getInstance(); c.set(2010, 11, 14); Date d2 = c.getTime(); Locale locBR = new Locale("pt", "BR");  // Brazil Locale locDK = new Locale("da", "DK");  // Denmark Locale locIT = new Locale("it", "IT");  // Italy System.out.println("def " + locBR.getDisplayCountry()); System.out.println("loc " + locBR.getDisplayCountry(locBR)); System.out.println("def " + locDK.getDisplayLanguage()); System.out.println("loc " + locDK.getDisplayLanguage(locDK)); System.out.println("D>I " + locDK.getDisplayLanguage(locIT)); 

This, on our JVM, produces

 def Brazil loc Brasil def Danish loc dansk D>I danese 

Given that our JVM's locale (the default for us) is us, the default for the country Brazil is "Brazil", and the default for the Danish language is "Danish". In Brazil, the country is called "Brasil", and in Denmark the language is called "dansk". Finally, just for fun, we discovered that in Italy, the Danish language is called "danese".

The NumberFormat Class

We'll wrap up this objective by discussing the NumberFormat class. Like the DateFormat class, NumberFormat is abstract, so you'll typically use some version of either getInstance() or getcurrencyInstance() to create a NumberFormat object. Not surprisingly, you use this class to format numbers or currency values:

 float f1 = 123.4567f; Locale locFR = new Locale("fr");          // France NumberFormat[] nfa = new NumberFormat[4]; nfa[0] = NumberFormat.getInstance(); nfa[1] = NumberFormat.getInstance(locFR); nfa[2] = NumberFormat.getCurrencyInstance(); nfa[3] = NumberFormat.getCurrencylnstance(locFR); for(NumberFormat nf : nfa)   System.out.println(nf.format(f1)); 

This, on our JVM, produces

 123.457 123,457 $123.46 123,46 ? 

Don't be worried if, like us, you're not set up to display the symbols for francs, pounds, rupees, yen, baht, or drachmas. You won't be expected to know the symbols used for currency: if you need one, it will be specified in the question. You might encounter methods other than the format method on the exam. Here's a little code that uses getMaximumFractionDigits(), setMaximumFractionDigits(),parse(), and setParseIntegerOnly():

 float f1 = 123.45678f; NumberFormat nf = NumberFormat.getInstance(); System.out.print(nf.getMaximumFractionDigits() + " "); System.out.print(nf.format(fl) + "  "); nf.setMaximumFractionDigits(5); System.out.println(nf.format(fl) + "  ") ; try {   System.out.println(nf.parse("1234.567"));   nf.setParselntegerOnly(true);   System.out.println(nf.parse("1234.567")); } catch (ParseException pe) {   System.out.println("parse exc"); } 

This, on our JVM, produces

 3  123.457  123.45678 1234.567 1234 

Notice that in this case, the initial number of fractional digits for the default NumberFormat is three: and that the format() method rounds f1's value, it doesn't truncate it. After changing nf's fractional digits, the entire value of f1 is displayed. Next, notice that the parse() method must run in a try/catch block and that the setParseIntegerOnly() method takes a boolean and in this case, causes subsequent calls to parse() to return only the integer part of Strings formatted as floating-point numbers.

As we've seen, several of the classes covered in this objective are abstract. In addition, for all of these classes, key functionality for every instance is established at the time of creation. Table 6-3 summarizes the constructors or methods used to create instances of all the classes we've discussed in this section.

Table 6-3: Instance Creation for Key java.text and java.util Classes

Class

Key Instance Creation Options

 util.Date 

 new Date(); new Date(long millisecondsSince010170); 

 util.Calendar 

 Calendar.getInstance(); Calendar.getInstance(Locale); 

 util.Locale 

 Locale.getDefault(); new Locale(String language); new Locale(String language,String country); 

 text.DateFormat 

 DateFormat.getInstance(); DateFormat.getDateInstance(); DateFormat.getDateInstance(style); DateFormat.getDateInstance(style, Locale); 

 text.NumberFormat 

 NumberFormat.getInstance() NumberFormat.getInstance(Locale) NumberFormat.getNumberInstance() NumberFormat.getNumberlnstance(Locale) NumberFormat.getCurrencyInstance() NumberFormat.getCurrencyInstance(Locale) 




SCJP Sun Certified Programmer for Java 5 Study Guide Exam 310-055
SCJP Sun Certified Programmer for Java 5 Study Guide (Exam 310-055) (Certification Press)
ISBN: 0072253606
EAN: 2147483647
Year: 2006
Pages: 131

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net