|
![]() |
![]() |
![]() |
![]() |
There are quite a few classes in the java.util package that are involved with dates and times, including the Date class, the Calendar class, and the GregorianCalendar class. In spite of the class name, a Date class object actually defines a particular instant in time to the nearest millisecond, measured from January 1, 1970, 00:00:00 GMT. Since it is relative to a particular instant in time, it also corresponds to a date. The Calendar class is the base class for GregorianCalendar, which represents the sort of day/month/year calendar everybody is used to, and also provides methods for obtaining day, month, and year information from a Date object. A Calendar object is always set to a particular date – a particular instant on a particular date to be precise– but you can change it by various means. From this standpoint a GregorianCalendar object is more like one of those desk calendars that just show one date, and you can flip over the days, months, or years to show another date.
There is also the TimeZone class that defines a time zone that can be used in conjunction with a calendar, and that you can use to specify the rules for clock changes due to daylight saving time. The ramifications of handling dates and times are immense so we will only be able to dabble here, but at least you will get the basic ideas. Let's take a look at Date objects first.
With the Date class you can create an object that represents a given date and time. You have two ways to do this using the following constructors:
With either constructor you create a Date object that represents a specific instant in time to the nearest millisecond. Carrying dates around as the number of milliseconds since the dawn of the year 1970 won't grab you as being incredibly user-friendly – but we'll come back to how we can interpret a Date object better in a moment. The Date class provides three methods for comparing Date objects:
The equals() method returns true if two different Date objects represent the same date and time. Since the hashCode() method is also implemented for the class, you have all you need to use Date objects as keys in a hash table.
The DateFormat class is an abstract class that you can use to create meaningful String representations of Date objects. It isn't in the java.util package though – it's defined in the package java.text. There are four standard representations for the date and the time that are identified by constants defined in the DateFormat class. The effects of these will vary in different countries, because the representation for the date and the time will reflect the conventions of those countries. The constants in the DateFormat class defining the four formats are:
A Locale object identifies information that is specific to a country, a region, or a language. You can define a Locale object for a specific country, for a specific language, for a country and a language, or for a country and a language and a variant, the latter being a vendor or browser specific code such as WIN or MAC. When you are creating a Locale object you use ISO codes to specify the language and/or the country. The language codes are defined by ISO-639. Countries are specified by the country codes in the standard ISO-3166. You can find the country codes on the Internet at:
http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html
or at:
http://www.din.de/gremien/nas/nabd/iso3166ma/codlstp1/en_listp1.html
You can find the language codes at:
http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt
or at:
http://lcweb.loc.gov/standards/iso639-2/langhome.html
For some countries, the easiest way to specify the locale, if you don't have the ISO codes on the tip of your tongue, is to use the Locale objects defined within the Locale class. In Java 2 these are:
Because the DateFormat class is abstract, you can't create objects of the class directly, but you can obtain DateFormat objects by using any of the following static methods, each of which returns a value of type DateFormat:
When you've obtained a DateFormat object for the country and the style that you want, and the sort of data you want to format – the date or the time or both – you're ready to produce a String from the Date object.
All you need to do is to pass the Date object to the format() method for the DateFormat object. For example:
Date today = new Date(); // Object for now – today's date DateFormat fmt = getDateTimeInstance(Locale.FULL, Locale.US); String formatted = fmt.format(today);
After executing these statements, the String variable, formatted, will contain a full representation of the date and the time when the Date object, today, was created.
We can try out some dates and formats in a simple example.
This example will show the four different date formats for four countries:
// Trying date formatting import java.util.Locale; import java.util.Date; import java.text.DateFormat; public class TryDateFormats { public static void main(String[] args) { Date today = new Date(); Locale[] locales = {Locale.US, Locale.UK, Locale.GERMANY, Locale.FRANCE}; int[] styles = {DateFormat.FULL,DateFormat.LONG, DateFormat.MEDIUM,DateFormat.SHORT}; DateFormat fmt; String[] styleText = {"FULL", "LONG", "MEDIUM", "SHORT"}; // Output the date for each locale in four styles for(int i = 0; i < locales.length; i++) { System.out.println("\nThe Date for " + locales[i].getDisplayCountry() + ":"); for(int j = 0; j < styles.length; j++) { fmt = DateFormat.getDateInstance(styles[j], locales[i]); System.out.println( "\tIn " + styleText[j] + " is " + fmt.format(today)); } } } }
When I compiled and ran this it produced the following output:
The Date for United States: In FULL is Saturday, February 9, 2002 In LONG is February 9, 2002 In MEDIUM is Feb 9, 2002 In SHORT is 2/9/02 The Date for United Kingdom: In FULL is 09 February 2002 In LONG is 09 February 2002 In MEDIUM is 09-Feb-2002 In SHORT is 09/02/02 The Date for Germany: In FULL is Samstag, 9. Februar 2002 In LONG is 9. Februar 2002 In MEDIUM is 09.02.2002 In SHORT is 09.02.02 The Date for France: In FULL is samedi 9 fΘvrier 2002 In LONG is 9 fΘvrier 2002 In MEDIUM is 9 fΘvr. 2002 In SHORT is 09/02/02
How It Works
The program creates a Date object for the current date and time, and an array of Locale objects for four countries using values defined in the Locale class. It then creates an array of the four possible styles, and another array containing a String representation for each style that will be used in the output.
The output is produced in the nested for loops. The outer loop iterates over the countries, and the inner loop iterates over the four styles for each country. A DateFormat object is created for each combination of style and country, and the format() method for the DateFormat object is called to produce the formatted date string in the inner call to println().
There are a couple of ways you could change the program. You could initialize the locales [] array with the expression DateFormat.getAvailableLocales(). This will return an array of type Locale containing all of the supported locales, but be warned – there are a lot of them. You'll also find that the characters won't display for many countries because your machine doesn't support the country-specific character set. You could also use the method getTimeInstance() or getDateTimeInstance() instead of getDateInstance() to see what sort of output they generate.
Under the covers, a DateFormat object contains a DateFormatSymbols object that contains all the strings for the names of days of the week and other fixed information related to time and dates. This class is also in the java.text package. Normally you don't use the DateFormatSymbols class directly, but it can be useful when all you want are the days of the week.
The parse() method for a DateFormat object interprets a String object passed as an argument as a date and time, and returns a Date object corresponding to the date and the time. The parse() method will throw a ParseException if the String object can't be converted to a Date object, so you must call it within a try block.
The String argument to the parse() method must correspond to the country and style that you used when you obtained the DateFormat object. This makes it a bit tricky to use successfully. For example, the following code will parse the string properly:
Date aDate; DateFormat fmt = DateFormat.getDateInstance(DateFormat.FULL, Locale.US); try { aDate = fmt.parse("Saturday, July 4, 1998 "); System.out.println("The Date string is: " + fmt.format(aDate)); } catch(ParseException e) { System.out.println(e); }
This works because the string is what would be produced by the locale and style. If you omit the day from the string, or you use the LONG style or a different locale, a ParseException will be thrown.
The Gregorian calendar is the calendar generally in use today in the western world, and is represented by an object of the GregorianCalendar class. A GregorianCalendar object encapsulates time zone information, as well as date and time data. There are no less than seven constructors for GregorianCalendar objects, from the default that creates a calendar with the current date and time in the default locale for your machine, through to a constructor where you can specify the year, month, day, hour, minute, and second. The default suits most situations.
You can create a calendar with a statement such as:
GregorianCalendar calendar = new GregorianCalendar();
This will be set to the current instant in time, and you can retrieve this as a Date object by calling the getTime() method for the calendar:
Date now = calendar.getTime();
You can create a GregorianCalendar object encapsulating a specific date and/or time with the following constructors:
GregorianCalendar(int year, int month, int day)
GregorianCalendar(int year, int month, int day, int hour, int minute)
GregorianCalendar(int year, int month, int day,
int hour, int minute, int second)
The day argument is the day within the month, so the value can be from 1 to 28, 29, 30, or 31, depending on the month and whether it's a leap year or not. The month value is zero-based so January is 0 and December is 11.
The GregorianCalendar class is derived from the abstract Calendar class from which it inherits a large number of methods and static constants for use with these methods. The constants includes month values with the names JANUARY to DECEMBER so you could create a calendar object with the statement:
GregorianCalendar calendar = new GregorianCalendar(1967, Calendar.MARCH, 10);
The time zone and locale will be the default for the computer on which this statement executes. If you want to specify a time zone there is a GregorianCalendar constructor that accepts an argument of type TimeZone. The TimeZone class is also defined in the java.util package. You can get the default TimeZone object by calling the static getDefault() method, but if you are going to the trouble of specifying a time zone, you probably want something other than the default. To create a particular time zone you need to know its ID. This is a string specifying a region or country plus a location. For instance, here are some examples of time zone IDs:
Europe/
|
Asia/Novosibirsk |
Pacific/Guam |
America/Chicago |
Antarctica/
|
Atlantic/
|
Africa/Accra |
Indian/Comoro |
To obtain a reference to a TimeZone object corresponding to a given time zone ID, you pass the ID to the static getTimeZone() method. For instance, we could create a Calendar object for the Chicago time zone like this:
GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("America/Chicago"));
If you want to know what all the time zones IDs are, you could list them like this:
String[] ids = TimeZone.getAvailableIDs(); for(int i = 0 ; i<ids.length ; i++) System.out.println(ids[i]);
The calendar created from a TimeZone object will have the default locale. If you want to specify the locale explicitly, there's a constructor that accepts a Locale reference as the second argument. For example:
GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("America/Chicago"). Locale.US);
You can also create a Calendar object from a locale:
GregorianCalendar calendar = new GregorianCalendar(Locale.UK);
This will create a calendar set to the current time in the default time zone within the UK.
If you have a Date object available, there is a setTime() method that you can pass a Date object, to set a GregorianCalendar object to the time specified by the Date object:
calendar.setTime(date);
More typically you will want to set the date and/or time with explicit values such as day, month, and year, and there are several overloaded versions of the set() method for setting various components of the date and time. These are inherited in the GregorianCalendar class from its superclass, the Calendar class. You can set a GregorianCalendar object to a particular date like this:
GregorianCalendar calendar = new GregorianCalendar(); calendar.set(1995, 10, 29); // Date set to 29th November 1999
The three arguments to the set() method here are the year, the month, and the day as type int. You need to take care with this method as it's easy to forget that the month is zero-based with January specified by 0. Note that the fields reflecting the time setting within the day will not be changed. They will remain at whatever they were. You can reset all fields for a GregorianCalendar object to zero by calling its clear() method, so calling clear() before you call set() here would ensure the time fields are all zero.
The other versions of the set() method are:
set(int year, int month, int day, int hour, int minute)
set(int year, int month, int day, int hour, int minute, int second)
set(int field, int value)
It's obvious what the first two of these do. In each case the fields not explicitly set will be left at their original values. The third version of set() sets a field specified by one of the integer constants defined in the Calendar class for this purpose:
With the exception of AD and BC as noted in the table, the constants for field values are also defined in the Calendar class. Thus you can set the day of the week with the statement:
calendar.set(Calendar.DAY_OF_WEEK, Calendar.TUESDAY);
Of course, since a variable of type GregorianCalendar also has all these constants you could use the variable name, calendar, instead of the class name as the qualifier for the name of the constants here.
You can get information such as the day, the month, and the year from a GregorianCalendar object by using the get() method and specifying what you want as an argument. The possible arguments to the get() method are those defined in the table of constants above identifying calendar fields. All values returned are of type int. For example, you could get the day of the week with the statement:
int day = calendar.get(calendar.DAY_OF_WEEK);
You could now test this for a particular day using the constant defined in the class:
if(day == calendar.SATURDAY) // Go to game...
Since the values for day are integers, you could equally well use a switch statement:
switch(day) { case Calendar.MONDAY: // do the washing... break; case Calendar.MONDAY: // do something else... break; // etc... }
Of course, you might want to alter the current instant in the calendar, and for this you have the add() method. The first argument determines what units you are adding in, and you specify this argument using the same field designators as in the previous list. For example, you can add 14 to the year with the statement:
calendar.add(calendar.YEAR, 14); // 14 years into the future
To go into the past, you just make the second argument negative:
calendar.add(calendar.MONTH, -6); // Go back 6 months
You can increment or decrement a field of a calendar by 1 using the roll() method. This method modifies the field specified by the first argument by +1 or –1, depending on whether the second argument is true or false. For example, to decrement the current month in the object calendar, you would write:
calendar.roll(calendar.MONTH, false); // Go back a month
The change can affect other fields. If the original month was January, rolling it back by one will make the date December of the previous year.
Of course, having modified a GregorianCalendar object, you can get the current instant back as a Date object using the getTime() method that we saw earlier. You can then use a DateFormat object to present this in a readable form.
Checking the relationship between dates is a fairly fundamental requirement and you have three methods available for comparing Calendar objects:
These are very simple to use. To determine whether the object thisDate defines a time that precedes the time defined by the object today, you could write:
if(thisDate.before(today)) // Do something
Alternatively you could write the same thing as:
if(today.after(thisDate)) // Do something
It's time to look at how we can use calendars.
This example will deduce important information about when you were born. It uses the FormattedInput class to get input from the keyboard, so copy the class to the directory containing the source file for this example. Here's the code:
import java.util.GregorianCalendar; import java.text.DateFormatSymbols; class TryCalendar { public static void main(String[] args) { FormattedInput in = new FormattedInput(); // Get the date of birth from the keyboard System.out.println("Enter your birth date as dd mm yyyy: "); int day = in.readInt(); int month = in.readInt(); int year = in.readInt(); // Create birth date calendar – month is 0 to 11 GregorianCalendar birthdate = new GregorianCalendar(year, month-1,day); GregorianCalendar today = new GregorianCalendar(); // Today's date // Create this year's birthday GregorianCalendar birthday = new GregorianCalendar( today.get(today.YEAR), birthdate.get(birthdate.MONTH), birthdate.get(birthdate.DATE)); int age = today.get(today.YEAR) – birthdate.get(birthdate.YEAR); String[] weekdays = new DateFormatSymbols().getWeekdays(); // Get day names System.out.println("You were born on a " + weekdays[birthdate.get(birthdate.DAY_OF_WEEK)]); System.out.println("This year you " + (birthday.after(today) ?"will be " : "are ") + age + " years old."); System.out.println("This year your birthday "+ (today.before(birthday)? "will be": "was")+ " on a "+ weekdays[birthday.get(birthday.DAY_OF_WEEK)]); } }
I got the output:
Enter your birth date as dd mm yyyy: 5 12 1964 You were born on a Saturday This year you will be 34 years old. This year your birthday will be on a Saturday
How It Works
We start by prompting for the day, month, and year for a date of birth to be entered through the keyboard as integers. We then create a Calendar object corresponding to this date. Note the adjustment of the month – the constructor expects January to be specified as 0. We need a Calendar object for today's date so we use the default constructor for this. To compute the age this year, we just have to subtract the year of birth from this year, both of which we get from the GregorianCalendar objects.
To get at the strings for the days of the week, we create a DateFormatSymbols object and call its getWeekdays() method. This returns an array of eight String objects, the first of which is empty to make it easy to index using day numbers from 1 to 7. The second element in the array contains "Sunday". You can also get the month names using the getMonths() method.
To display the day of the week for the date of birth we call the get() method for the GregorianCalendar object birthdate, and use the result to index the weekdays[] array. To determine the appropriate text in the next two output statements, we use the after() and before() methods for Calendar objects to compare today with the birthday date this year.
![]() |
![]() |
![]() |