Tuesday, October 05, 2004

The GregorianCalendar class

One way to create an object representing an arbitrary date is to use the following constructor of the GregorianCalendar class, found in the java.util package:


GregorianCalendar(int year, int month, int date)


Note that for the month, January is 0, February is 1, and so on, until December, which is 11. Since those are not the numbers most of us associate with the months of the year, programs will probably be more readable if they use the constants of the parent Calendar class: JANUARY, FEBRUARY, and so on. So, to create an object representing the date that Wilbur and Orville Wright first flew their motored aircraft (December 17, 1903), you can use:



GregorianCalendar firstFlight = new GregorianCalendar(1903, Calendar.DECEMBER, 17);


For clarity's sake, you should use the preceding form. However, you should also learn how to read the shorter form, below. The following example represents the same December 17, 1903, date (remember, in the shorter form 11 represents December):



GregorianCalendar firstFlight = new GregorianCalendar(1903, 11, 17);


In the previous section, you learned how to turn Date objects into Strings. You will do the same again; but first, you need to convert a GregorianCalendar object to a Date. To do so, you will use the getTime() method, which GregorianCalendar inherits from its parent Calendar class. The getTime() method returns a Date corresponding to a GregorianCalendar object. You can put the whole process of creating a GregorianCalendar object, converting it to a Date, and getting and outputting the corresponding String in the following program:



import java.util.*;
import java.text.*;

public class Flight {

public static void main(String[] args) {
GregorianCalendar firstFlight = new GregorianCalendar(1903, Calendar.DECEMBER, 17);
Date d = firstFlight.getTime();
DateFormat df = DateFormat.getDateInstance();
String s = df.format(d);
System.out.println("First flight was " + s);
}
}


Sometimes it is useful to create an instance of the GregorianCalendar class representing the day the instance was created. To do so, simply use the GregorianCalendar constructor taking no arguments, such as:



GregorianCalendar thisday = new GregorianCalendar();


A sample program to output today's date, starting with a GregorianCalendar object is:



import java.util.*;
import java.text.*;

class Today {
public static void main(String[] args) {
GregorianCalendar thisday = new GregorianCalendar(); Date d = thisday.getTime();
DateFormat df = DateFormat.getDateInstance();
String s = df.format(d);
System.out.println("Today is " + s);
}
}


Note the similarities between the Date() constructor and the GregorianCalendar() constructor: both create an object, which in simple terms, represents today.

Date manipulation
The GregorianCalendar class offers methods for manipulating dates. One useful method is add(). With the add() method, you can add such time units as years, months, and days to a date. To use the add() method, you must supply the field being increased, and the integer amount by which it will increase. Some useful constants for the fields are DATE, MONTH, YEAR, and WEEK_OF_YEAR. The add() method is used in the program below to calculate a date 80 days in the future. Phileas Fogg, the central character in Jules Verne's Around the World in 80 Days, could have used such a program to calculate a date 80 days from his departure on October 2, 1872:



import java.util.*;
import java.text.*;

public class World {
public static void main(String[] args) {
GregorianCalendar worldTour = new GregorianCalendar(1872, Calendar.OCTOBER, 2);
worldTour.add(GregorianCalendar.DATE, 80);
Date d = worldTour.getTime();
DateFormat df = DateFormat.getDateInstance();
String s = df.format(d);
System.out.println("80 day trip will end " + s);
}
}


While the example is a bit fanciful, adding days to a date is a common operation: video rentals can be due in 3 days, a library may lend books for 21 days, stores frequently require purchased items to be exchanged within 30 days. The following program shows a calculation using years:



import java.util.*;
import java.text.*;

public class Mortgage {
public static void main(String[] args) {
GregorianCalendar mortgage = new GregorianCalendar(1997, Calendar.MAY, 18);
mortgage.add(Calendar.YEAR, 15);
Date d = mortgage.getTime();
DateFormat df = DateFormat.getDateInstance();
String s = df.format(d);
System.out.println("15 year mortgage amortized on " + s); }
}


One important side effect of the add() method is that it changes the original date. Sometimes it is important to have both the original date and the modified date. Unfortunately, you cannot simply create a new GregorianCalendar object set equal to the original. The reason is that the two variables have a reference to one date. If the date is changed, both variables now refer to the changed date. Instead, a new object should be created. The following example will demonstrate this:



import java.util.*;
import java.text.*;

public class ThreeDates {
public static void main(String[] args) {
GregorianCalendar gc1 = new GregorianCalendar(2000, Calendar.JANUARY, 1);
GregorianCalendar gc2 = gc1;
GregorianCalendar gc3 = new GregorianCalendar(2000, Calendar.JANUARY, 1);
//Three dates all equal to January 1, 2000

gc1.add(Calendar.YEAR, 1);
//gc1 and gc2 are changed

DateFormat df = DateFormat.getDateInstance();

Date d1 = gc1.getTime();
Date d2 = gc2.getTime();
Date d3 = gc3.getTime();

String s1 = df.format(d1);
String s2 = df.format(d2);
String s3 = df.format(d3);

System.out.println("gc1 is " + s1);
System.out.println("gc2 is " + s2);
System.out.println("gc3 is " + s3);
}
}


After the program is run, gc1 and gc2 are changed to the year 2001 (because both objects are pointing to the same underlying date representation, which has been changed). The object gc3 is pointing to a separate underlying date representation, which has not been changed.

Calculating review dates
At this point, you have a program based on a real-world example. This particular program will calculate the dates for reviewing material. For example, while reading this article, you might come across some points you want to remember. Unless you have photographic memory, you will likely find that periodically reviewing the new material will aid in remembering it. One reviewing system, discussed in Kurt Hanks and Gerreld L. Pulsipher's Five Secrets to Personal Productivity, suggests briefly covering the material immediately after it is first seen, then after one day, one week, one month, three months, and one year. For this article, you would give it a quick review immediately, another tomorrow, then one week, one month, three months, and one year from now. Our program will calculate the dates.

To be most useful, the program would be incorporated in PIM (Personal Information Manager) software, which would run the program and schedule the reviews. The getDates() method in the following ReviewDates program would be useful for integrating with electronic software as it returns an array of dates (the review dates). Additionally, you can return individual dates using the methods getFirstDay(), getOneDay(), getOneWeek(), getOneMonth(), and getOneYear(). While it is beyond the scope of this article to integrate the ReviewDates class with a PIM, the ReviewDates class does show how to calculate dates based on elapsed time. Now you can easily modify it for other operations that require elapsed time, such as library loans, tape rentals, and mortgage calculations. First, the ReviewDates class is shown below:



import java.util.*;
import java.text.*;

public class ReviewDates {
private GregorianCalendar firstDay, oneDay, oneWeek, oneMonth, oneQuarter, oneYear;
final int dateArraySize = 6;

ReviewDates(GregorianCalendar gcDate) {
int year = gcDate.get(GregorianCalendar.YEAR);
int month = gcDate.get(GregorianCalendar.MONTH);
int date = gcDate.get(GregorianCalendar.DATE);

firstDay = new GregorianCalendar(year, month, date);
oneDay = new GregorianCalendar(year, month, date);
oneWeek = new GregorianCalendar(year, month, date);
oneMonth = new GregorianCalendar(year, month, date);
oneQuarter = new GregorianCalendar(year, month, date);
oneYear = new GregorianCalendar(year, month, date);

oneDay.add(GregorianCalendar.DATE, 1);
oneWeek.add(GregorianCalendar.DATE, 7);
oneMonth.add(GregorianCalendar.MONTH, 1);
oneQuarter.add(GregorianCalendar.MONTH, 3);
oneYear.add(GregorianCalendar.YEAR, 1);
}

ReviewDates() {
this(new GregorianCalendar());
}

public void listDates() {
DateFormat df = DateFormat.getDateInstance(DateFormat.LONG);
Date startDate = firstDay.getTime();
Date date1 = oneDay.getTime();
Date date2 = oneWeek.getTime();
Date date3 = oneMonth.getTime();
Date date4 = oneQuarter.getTime();
Date date5 = oneYear.getTime();

String ss = df.format(startDate);
String ss1 = df.format(date1);
String ss2 = df.format(date2);
String ss3 = df.format(date3);
String ss4 = df.format(date4);
String ss5 = df.format(date5);

System.out.println("Start date is " + ss);
System.out.println("Following review dates are:");
System.out.println(ss1);
System.out.println(ss2);
System.out.println(ss3);
System.out.println(ss4);
System.out.println(ss5);
System.out.println();
}

public GregorianCalendar[] getDates() {
GregorianCalendar[] memoryDates = new GregorianCalendar[dateArraySize];
memoryDates[0] = firstDay;
memoryDates[1] = oneDay;
memoryDates[2] = oneWeek;
memoryDates[3] = oneMonth;
memoryDates[4] = oneQuarter;
memoryDates[5] = oneYear;
return memoryDates;
}

public GregorianCalendar getFirstDay() {
return this.firstDay;
}

public GregorianCalendar getOneDay() {
return this.oneDay;
}

public GregorianCalendar getOneWeek() {
return this.oneWeek;
}

public GregorianCalendar getOneMonth() {
return this.oneMonth;
}

public GregorianCalendar getOneQuarter() {
return this.oneQuarter;
}

public GregorianCalendar getOneYear() {
return this.oneYear;
}
}


An example of a program that uses the ReviewDates class to make a simple listing of review dates is shown below:



import java.util.*;

public class ShowDates {
public static void main(String[] args) {
ReviewDates rd = new ReviewDates();
rd.listDates();

GregorianCalendar gc = new GregorianCalendar(2001, Calendar.JANUARY, 15);
ReviewDates jan15 = new ReviewDates(gc);
jan15.listDates();
}
}



Conclusion
This article has introduced three important classes for working with dates: Date, DateFormat, and GregorianCalendar. These classes let you create dates, change them into Strings, and make elementary calculations with dates. In terms of working with dates in Java, this article has only scratched the surface. However, the classes and methods that I have introduced here not only serve as springboard for more advanced learning, but in themselves can also handle many common date-related tasks.

No comments: